仓库依赖图驱动的改动规划:让编程 Agent 先算影响闭包再写代码
目录相邻不等于依赖相关。本文把构建、符号、配置和运行时边组织成带版本的仓库图,让编程 Agent 在动手前计算影响闭包、阶段顺序和回滚边界。
本文要点
- 主题聚焦:AI Agent、TypeScript、DevOps
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
编程 Agent 接到“给公共类型增加一个字段”时,按目录搜索通常只能找到显式 import。真正受影响的还可能包括代码生成目标、运行时注册表、配置读取方、数据库迁移、测试夹具和另一个语言的客户端。先写代码再靠编译错误扩圈,会把规划变成试错,并且静默兼容问题不会产生编译错误。
依赖图驱动规划的目标不是再画一张仓库地图。编程 Agent 的仓库地图回答“有哪些模块和入口”,本文进一步回答“从这次契约变化出发,必须检查哪些节点、按什么顺序修改、哪些未知边会阻止自动执行”。
本文命令固定在 Linux/GNU CI 容器(Bash、GNU coreutils、Git)执行;macOS/Windows runner 必须使用同一容器。
图中的边必须带类型和证据
把包、构建目标、公共符号、schema、生成器、配置键和部署单元视为不同节点。边至少区分 imports、implements、generates、reads-config、publishes-event、migrates-data 和 loads-dynamically。每条边保存来源文件、提取器版本、源提交和置信度,不能只有 A -> B。
构建系统提供包级真相,编译器或 LSP 提供符号级引用,运行日志与注册配置补充动态边。三者不能互相替代:静态图看不到字符串加载的插件,动态覆盖也不能证明从未执行的分支没有依赖。无法解析的 glob、反射、模板和环境变量进入 unknownEdges,而不是被图悄悄丢弃。
{
"sourceCommit": "8f61c2a",
"seed": "//libs/contracts:user-v2",
"required": ["//apps/api", "//sdk/typescript"],
"inspect": ["//jobs/export"],
"unknownEdges": ["plugins/*:runtime-load"],
"graphDigest": "sha256:4a12..."
}
从变更种子计算双向影响闭包
规划器先把需求映射到明确种子,例如符号、schema 字段或构建目标,再向上找消费者、向下找生成源与运行依赖。公共接口变更不能只取反向 import:还要包含实现者、序列化边界、兼容适配器与发布单元。删除文件时必须查询基线图,因为 HEAD 图中旧节点已经不存在。
在使用 Bazel 的仓库中,可以从冻结基线验证反向依赖;Nx 项目则可用 affected 结果作为包级输入:
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
命令、工具版本、图 digest 和两个 Git SHA 一起进入计划工件。项目只采用其中与自身构建系统一致的命令,不能把示例工具输出拼成伪精确结果。若改动后 HEAD、lockfile 或工作区配置变化,旧计划立即失效。
闭包节点分为 required、inspect 和 unknown。直接消费者、生成目标和发布契约属于 required;低置信动态边属于 inspect;解析失败与跨仓库边属于 unknown。任何高风险 unknown 都禁止 Agent 自动改写,先由 owner 补边或确认扩大范围。
用强连通分量决定落地顺序
图不只决定读哪些文件,也决定迁移次序。无环部分按拓扑顺序执行;循环依赖先折叠成强连通分量,作为一个审阅单元。破坏性契约采用 expand-migrate-contract:先发布同时接受旧新格式的提供方,再迁移消费者,确认旧路径使用量归零,最后删除兼容层。
计划应列出每一阶段的输入、可观察完成条件和回滚点。例如 schema 阶段只新增可选字段,客户端阶段保持旧字段读取,清理阶段要求连续七天旧字段调用为零。这样 Agent 不能在一个 PR 里同时修改提供方、所有消费者和删除旧格式,导致无法独立验证。
用计划差分约束实际补丁
完成修改后重新生成图和影响闭包,将实际触碰节点与批准计划比较。出现计划外文件、公开边变化或新的强连通分量时,停止执行并重新审批。计划内节点未修改也要说明原因,防止遗漏被“测试通过”掩盖。
验证至少包括构建图查询、所有 required 目标的构建与测试、公开契约检查,以及编程 Agent 的测试影响分析提供的选择性回归。最终合并证据仍遵循编程 Agent 的改动验证门,但验证集合必须能追溯到图中的具体边。
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
第二条命令要求 CI 分别从可信工件恢复批准计划、从当前 HEAD 重新计算实际计划;Agent 无权在失败后重写前者。工具查询失败、图版本落后或 unknown 未清零时,安全回退是扩大到相关工作区或全仓验证,不是返回空影响集。
回滚以阶段为单位。尚未发布的补丁直接丢弃隔离分支;已合并阶段用 git revert <sha> 生成反向提交,并按同一依赖闭包重跑验证。数据或消息已经扩展后,不得先回滚提供方而让新消费者失去兼容能力。大型仓库的执行器可建立在Monorepo 工具链之上,但可靠性来自带证据的边、可冻结的计划和能独立撤销的阶段。
Related