Declared vs inferred dependencies in change-impact analysis
Declared vs inferred dependencies in change-impact analysis: what task links and import graphs each catch, where each is blind, how to combine them.
Declared vs inferred dependencies in change-impact analysis comes down to who supplies the links: declared dependencies are recorded on purpose by people or agents, such as a task link or a note that a decision rests on a file, while inferred dependencies are read by a tool from the code itself, such as imports and call sites. Neither is complete. Declared links capture intent and things code cannot show, like a business rule or a planned order of work, but they are only as good as the person who remembered to record them. Inferred links are mechanical and thorough within one language and repository, but they miss runtime wiring and say nothing about why the coupling exists. For AI-assisted work, where agents change shared code quickly, the practical answer is to use both and treat every disagreement between them as a finding. This page compares the two and shows how to combine them.
Declared dependencies: what people write down
A declared dependency is an explicit record: a task link, a prerequisite in a plan, a depends-on field, a note that a document supports a decision, an ownership file, a service catalog entry. Someone chose to write it.
Strengths. Declared links carry meaning. "Export depends on nearest-cent rounding" says what the dependency is about, not just that two files touch. They cover things no parser can see: a downstream team reading your CSV, a migration that must run before a feature flag flips, a decision that constrains three tasks. They also work across languages, repositories and non-code artifacts.
Blind spots. They decay. Nobody declares the import they add in a hurry, and agents rarely update dependency records unless told to. Declarations can also be wrong the other way, listing links that no longer exist, which makes impact lists noisy until people stop reading them.
The failure to remember is silent omission. A missing declaration does not raise an error. It produces a shorter impact list, and a short list looks like good news. In the probe described in the blast radius article, a query over declared links nominated two cards and missed the one feature that actually broke [D6].
Inferred dependencies: what tools read from code
An inferred dependency is derived from the artifacts themselves: static import graphs, call graphs, symbol references from a language server, build-system targets, or runtime traces collected while tests run.
Strengths. Inference does not depend on anyone's memory. Run the same analysis twice and you get the same answer, and it updates as soon as the code changes. For a question like "who calls cents()?", a reference search is faster and more complete than any task tracker.
Blind spots. Static inference misses anything wired at runtime: dynamic imports, plugin registries, reflection, dependency injection and functions referenced by name in configuration. It misses data contracts: a consumer that parses your CSV or JSON has no import of your code at all. It usually stops at the repository boundary, so multi-repo projects need extra work. Runtime traces only see the paths your tests exercised.
Inference also has no notion of intent. It can tell you that checkout and export both call the helper. It cannot tell you that one needs truncation and the other needs rounding, which is the fact that turns a one-line change into a regression. That knowledge has to be written down by someone.
Side by side
Source: declared links come from people and agents recording them; inferred links come from parsing or tracing code.
Coverage: declared links cover anything someone thought of, including non-code work; inferred links cover everything the analyzer understands and nothing else.
Freshness: declared links go stale when code changes and nobody updates them; inferred links are as fresh as the last analysis run.
Meaning: declared links can say why two things are coupled; inferred links only say that they are.
Typical miss: declared analysis misses the import nobody recorded; inferred analysis misses the consumer that reads your output without importing your code.
Effort: declared links need discipline at write time; inferred links need tooling for each language and repository.
The two are complementary. Each is strong exactly where the other is weak, so the most useful signal is not either list on its own but the difference between them. The same split shows up in context retrieval, compared in relationship vs semantic retrieval.
Combining both in practice
A workable routine for any change to shared code, with or without special tooling:
Step 1: Build the inferred list. Use your editor's find-references, a search for the import, or your build tool's reverse dependency query for every changed symbol.
Step 2: Build the declared list. Pull the tasks, features or services your tracker links to the changed module.
Step 3: Reconcile. Anything on the inferred list but not the declared list is a missing declaration: add it, with one line on what the consumer expects. Anything declared but not inferred is either a runtime or data dependency (keep it and say so) or a stale link (remove it).
Step 4: Run checks for the union of both lists, not either list alone.
Over time this turns inference into a feeder for declarations. Agents can help with steps 1 and 3, as long as a person approves the new links, because an agent that adds dependency records is making claims about the system that deserve the same review as code. Keeping those declarations next to the work is the subject of task dependency graphs for AI agents.
HOW BRAIN FLUID DOES IT
BRAIN FLUID works on the declared side of this comparison [D6]. Dependency and blocker details are kept with project planning [N03], and Graph lets you explore recorded relationships, with results that depend on the selected project data [C1d]. The declared-relationship impact query, tested on the RC2 package, follows recorded links from a changed source through its evidence and claims to dependent cards, and states when its coverage is incomplete [D6]. It does not infer dependencies from imports: in testing it missed a module that imported the changed function without a recorded link [D6]. Evidence freshness flags recorded evidence whose supporting files changed [C6]. Inferred dependencies still come from your own tools, such as find-references or a build graph, and reconciling the two lists is a manual step [D6].
- D6 Declared-relationship impact query (tested package)
- Query recorded relationships from a changed source through its evidence and claims to the cards that depend on it, with stale evidence flagged and incomplete coverage stated. Evidence: Tested on the 1.8.5 RC2 package, October 30, 2026: 8 change-impact graph tests and a realistic regression probe.
- N03 Planning and My Work
- Keep assignee, reviewer, due-date, blocker and dependency details with project planning, and use My Work to focus attention. Evidence: Implemented; source and plan records
- C1d Graph
- Explore recorded relationships in Graph; availability and results depend on the selected project data. Evidence: Current source tests pass, including recovery from an unavailable service; an October 17 installed HTTP 503 is historical
- C6 Evidence freshness
- See whether recorded evidence still matches its supporting files. Evidence: Implemented; source-documented and retained knowledge tests
QUESTIONS
- What is the difference between a declared and an inferred dependency?
- A declared dependency is recorded on purpose by a person or agent, such as a task link or a prerequisite in a plan. An inferred dependency is derived by a tool from the code, such as an import or a call site. Declared links carry intent but can be missing; inferred links are mechanical but miss runtime wiring and data contracts.
- Can static analysis find every dependency in a codebase?
- No. Static analysis misses dynamic imports, plugin registries, reflection, functions named in configuration and consumers that only read your output format. It also usually stops at the repository boundary. Runtime tracing helps, but only for paths your tests actually exercise. Treat any inferred dependency list as a strong starting point, not a complete one.
- Should AI agents update dependency records themselves?
- They can propose them, and that is useful because agents see imports while they edit. But a dependency record is a claim about the system, so a person should approve it like any other change. Unreviewed links make impact lists noisy, and noisy lists stop being read, which defeats the point of recording them.
RELATED GUIDES
RELATED HARNESS PAGES
BRAIN FLUID AI HARNESS
COMING SOON
Verified against the v1.8.5 development candidate (October 30, 2026 build) (reviewed October 30, 2026)
Free Windows software, not released yet. The download opens on the product page when the release is approved, with nothing to sign up for.