
修改一个功能需要动哪些文件?输入一个 operationId,答案即刻呈现。
问题
在全栈应用中,“一个功能"不会只存在于一个文件里。
假设你需要修改"接受提案(AcceptProposal)“这个功能。它存在于 API 规范中、服务逻辑中、数据库 schema 中、授权策略中、状态转移图中、外部函数调用中、测试场景中,以及前端中。
过去,要搞清楚这些完整范围,只有两种方法:
- 反复执行 Grep 数十次
- 手动追踪代码
两种方法都慢,都会遗漏。尤其是跨层引用——从 API 规范到服务层、从服务层到 DB schema、从服务层到授权策略——靠人工不遗漏地追踪,现实上几乎做不到。
但如果各层的源文件已经在符号层面相互引用,那么只需顺着这些引用走,完整范围就会自动浮现。
Feature Chain 是什么
Feature Chain 是从一个 API 功能(operationId)出发,提取所有关联源节点的工具。
以一个 operationId 为起点,沿源文件间的符号引用追踪,一次性输出所有相关文件及行号。数十次 Grep 被一条命令取代。
fullend chain AcceptProposal specs/
── Feature Chain: AcceptProposal ──
OpenAPI api/openapi.yaml:296 POST /proposals/{id}/accept
SSaC service/proposal/accept_proposal.ssac:19 @get @empty @auth @state @put @call @post @response
DDL db/gigs.sql:1 CREATE TABLE gigs
DDL db/proposals.sql:1 CREATE TABLE proposals
DDL db/transactions.sql:1 CREATE TABLE transactions
Rego policy/authz.rego:3 resource: gig
StateDiag states/gig.md:7 diagram: gig → AcceptProposal
StateDiag states/proposal.md:6 diagram: proposal → AcceptProposal
FuncSpec func/billing/hold_escrow.go:8 @func billing.HoldEscrow
Gherkin scenario/gig_lifecycle.feature:4 Scenario: Happy Path - Full Gig Lifecycle
Gherkin scenario/gig_lifecycle.feature:42 Scenario: Unauthorized Access
一个功能的完整结构尽在一屏之内。未关联的层不会出现在输出中。
为何可行
这不是魔法。之所以可行,是因为源文件之间本来就存在相互引用。
在 fullend 框架中,各 SSOT(Single Source of Truth)层会以符号方式指向其他层:
- SSaC 的
@get Model.Method→ DDL 表 - SSaC 的
@auth action resource→ Rego 授权策略 - SSaC 的
@state diagramID→ Mermaid 状态图 - SSaC 的
@call pkg.Func→ Func Spec 实现体 - OpenAPI 的 operationId → SSaC 文件名
- Gherkin 的 action step → operationId
- STML 的 endpoint → OpenAPI path
这些引用最初是为 crosscheck——验证各 SSOT 之间一致性的工具——而设计的。由于 crosscheck 已经在解析这些引用,复用同一套基础设施,仅需图遍历便可提取出 feature chain。
遍历路径
以 operationId 为起点,引用图展开如下:
operationId (起点)
├── OpenAPI → path + method
├── SSaC → 服务函数文件
│ ├── @get → DDL 表
│ ├── @auth → Rego 策略规则
│ ├── @state → Mermaid stateDiagram 转移
│ ├── @call → Func Spec 实现体
│ └── @publish → 队列订阅者
├── Gherkin → 引用该 operationId 的场景
└── STML → 引用该 endpoint 的前端文件
每个分支只跟随一层符号引用。这是广度优先而非深度优先的遍历。一个功能在哪些层留下了痕迹,一览无余。
它改变了什么
确定修改范围
“修改这个功能需要动哪里?”
为了回答这个问题,我们要读代码、跑 Grep、问同事。Feature Chain 用一条命令取代了这一切。只要符号引用存在,就不会遗漏任何文件。
AI 代码修改
让 AI 修改功能时,最难的事是"告知修改范围”。需要把所有相关文件都放进上下文窗口,AI 才能准确修改,而判断哪些文件相关,本身就要靠人。
有了 Feature Chain,情况就不同了。只需提供一个 operationId,完整的修改范围就会自动识别出来。交给 AI 的上下文,不再有遗漏。
代码审查
在 review PR 时,一旦怀疑"修改了这个功能,那个文件是不是也该改?",只需对照 chain 即可立刻确认。层间的不一致,由结构而非人来捕获。
新人上手
当新加入的开发者说"我想了解 AcceptProposal 是怎么运作的”,把一个 Feature Chain 给他看就够了。从 API 到 DB、从授权策略到测试场景——功能的全貌一目了然。
为何选择 operationId
起点的选择至关重要。Feature Chain 选择了 operationId。
原因很简单。在全栈应用中,功能的单位是 API endpoint。用户点击按钮,API 被调用,API 执行服务逻辑,读取 DB,校验授权,触发状态转移。这一切流程的起点,就是 operationId。
operationId 已经在 OpenAPI 规范中定义,是全团队共享的名称。说"需要修改 AcceptProposal",后端开发者、前端开发者、QA 想到的都是同一件事。用这个通用的名称贯穿整个技术栈,是 Feature Chain 的设计初衷。
前提条件
Feature Chain 能够运作,需要满足前提:
源文件之间必须以符号方式相互引用。 SSaC 的
@get、@auth、@state、@call指令必须显式指向其他 SSOT。如果引用是隐式的——例如 DB 表名只以字符串形式存在于代码中——则无法追踪。必须通过 crosscheck。 Feature Chain 沿符号引用遍历,若引用无效则会产生错误结果。crosscheck 保证引用的一致性,Feature Chain 在此基础上进行遍历。
这就是 Feature Chain 不是通用工具的原因。它无法应用于任意项目。只有在源文件间引用经过设计的项目中——如 fullend 这种各 SSOT 显式相互指向的结构——才能运作。
未来:GEUL + SILK
目前,Feature Chain 通过逐一遍历各 SSOT 解析器进行探索,分别调用 SSaC 解析器、DDL 解析器、Rego 解析器、Mermaid 解析器,再汇总结果。
当所有 SSOT 都转换为 GEUL 图之后,Feature Chain 将变成单一索引查询。通过 SILK 的 SIDX 按位 AND 运算,一次查询即可提取与 operationId 关联的所有节点。
从逐解析器遍历到图查询。Feature Chain 的接口不变,但内部将发生根本性的变化。
小结
在全栈应用中,“功能"不在一个文件里。它跨越多个层,而这些层相互引用。Feature Chain 顺着这些引用,自动提取一个功能的完整范围。
只需输入一个 operationId,从 API 规范到 DB schema、从授权策略到测试场景——数十次 Grep 被一条命令取代。