跳到正文
← 返回博客
ESSAY / 思考

同一条边,两种事实:静态图谱与运行时追踪

静态关系说明代码允许什么,运行时记录说明样本经过什么;本文建立冲突模型,不声称已经完成实测。

以下内容是基于现有图谱方法推出的设计分析,不是一次已经发生的线上冲突记录。

对一条关系来说,至少需要保留两个独立事实:

static_resolved
runtime_observed

前者回答源码与注册关系能否解析出这条边;后者回答某一批运行样本中是否记录到它。把二者合并成一个 exists=true/false,会丢掉最重要的信息:代码允许存在,不代表当前样本经过;当前样本经过,也不代表静态提取器已经理解它。

一条边需要两个事实字段

当前业务图谱会处理 View、Logic、Workflow、DSL、Action、State、接口与数据关系。不同来源能够回答的问题并不相同:

来源可以确认的内容无法单独确认的内容
TypeScript AST导入、继承、模型引用、部分事件键动态分支是否真实执行
DSL / Workflow组件安装、业务名称、订阅与转换关系当前样本是否经过
运行时追踪某批请求的发送方、接收方和结果未观察关系是否不存在
数据库元数据表、字段和控制器映射字段的完整业务语义
人工业务定义代码未表达的流程含义当前代码是否仍遵守定义

静态关系稳定、可重复,也适合构建阶段检查;它通常看不到分支可达性、动态名称和真实流量。运行时追踪能看到一次实际执行,却只代表观测窗口与采样范围。

所以“存在”和“被观察到”不应该互相覆盖。

四种组合不能使用同一结论

静态解析运行时观察暂时解释禁止直接推出
两种来源在当前版本与样本上相互印证所有分支都已覆盖
关系已声明,但当前窗口未观察这一定是死代码
动态关系、提取缺口或版本漂移运行时事件已经是正式架构
当前没有证据关系绝对不存在

还有一种不属于关系冲突的情况:静态图来自一次构建,追踪来自另一个版本。缺少构建摘要、生成时间和 trace 版本时,两份数据根本不可比较。

这张矩阵的作用不是给每条边计算一个漂亮置信度,而是决定下一步应该检查源码、提取器、采样窗口还是版本对齐。

来源、版本和观测窗口必须保留

建议的边记录至少包含:

from
to
relation
static_evidence[]
runtime_observation_count
first_observed_at
last_observed_at
build_version
trace_version
status

status 可以表达:

declared
statically_resolved
runtime_observed
conflicted
stale
unresolved

这是建议的数据模型,不是当前系统已经实现的 schema。

状态也不能替代原始来源。conflicted 必须能够回到源码位置、构建版本和原始事件;否则它只是另一个无法解释的标签。运行时记录还需要采样率与丢失计数,没有丢失计数就无法区分“没有发生”和“发生但没有被记录”。

建图本身如何从大图收敛到一次修改的影响范围,由《从按钮事件到最小业务子图》负责。本文只处理多来源关系不一致时如何保留分歧。

一个尚未执行的最小实验

第一轮不需要拿完整业务图谱计算准确率,只需构造四条最小链:

  1. 静态可解析且实际执行;
  2. 静态存在但条件永远不满足;
  3. 使用动态名称注册,运行时可见;
  4. 旧版本存在、当前版本已经删除。

静态提取器与运行时追踪分别输出结果,再由人工标注关系语义。验收重点不是一个总准确率,而是错误类型能否被解释:漏掉动态关系、把类型引用误判成业务调用、把未触发路径误判为死代码,或因版本漂移制造冲突。

追踪本身也需要进入实验变量。同步日志可能改变时序,大量采集可能影响性能,关联 ID 也可能在异步边界丢失。只有记录采样、开销和丢失,运行时数据才有资格被称为观测事实。

这篇文章的停止位置

现有材料能够支撑多来源冲突模型和上述实验设计,不能支撑动态关系占比、追踪开销、静态命中率或图谱漂移速度。

在出现一条包含源码位置、运行版本、观测窗口与原始事件的脱敏冲突样本以前,这篇文章保持 essay,不把设计矩阵包装成已经完成的 lab