mcpField
F
fallow-review

fallow-review

github.com/fallow-rs测试与质量137908 次安装今天更新
代码仓库

关于 fallow-review

fallow-review 是用于代码审查的技能,将变更集转为基于依赖图的审查摘要,帮助审查者聚焦需要判断的结构性问题。它通过图快照和信号标识验证 Agent 的审查意见,并与负责 CI 门禁的 audit 命令区分。

主要功能

  1. 01按注意力评分排列变更单元
  2. 02从审查判断中排除确定性发现
  3. 03提取结构性决策问题
  4. 04生成带图快照的 Agent 审查指南
  5. 05校验审查意见的信号与快照

适用场景

  1. 01合并前审查分支或差异
  2. 02梳理自动编码后仍需判断的问题
  3. 03生成可回传给代码作者的审查意见

MCP 相关

README 提及 MCP 工具 decision_surface,用于呈现与 CLI 相同的依赖决策。其余 MCP 交互细节未在摘录中说明。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/fallow-rs/fallow-skills --skill fallow-review

安装后在 Claude Code 中输入/fallow-review确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
references/
production-runtime-data.md
tradeoff-elicitation.md

详细介绍

Fallow Review:由图谱支撑的代码审查

fallow review 会将一组变更转换为一份确定性、基于图谱的审查简报,以及一个 Agent 合约闭环。它回答的是“我该看哪里?哪些调用确实需要人来判断?”,而不是“CI 会因此阻止合并吗?”(负责门禁的是 fallow audit)。review 始终以 0 退出,因此无论审查结果如何,都可以安全运行。

它依次完成以下四项工作:

  • 排除:报告变更文件中的死代码、复杂度、重复代码和样式问题,并将其排除在判断闭环之外,避免把注意力浪费在已有确定性检查负责的内容上。
  • 聚焦:按综合关注度评分(扇入/扇出、风险区域、变更形态)为变更文件中的单元排序,并标注 review-here / not-prioritized;同时提供完整的 deprioritized 逃生列表,确保没有内容被隐藏。
  • 梳理结构:从差异中提取少数重要的结构性决策,将每项决策表述为判断问题;数量限制在适合工作记忆的范围内,并且每项都锚定到 fallow 发出的一个 signal_id。
  • 指引:向 Agent 提供基于图谱生成的摘要、审查方向、图谱快照固定标识,以及需要返回的确切判断格式。

适用场景

  • 合并前审查 PR、分支或差异(由 AI 生成或人工编写)。
  • Agent 完成工作并移除其能处理的 fallow 发现项后,用于呈现剩下需要人或 Agent 判断的内容。
  • 生成可进行行内审查的判断,并将其反馈给编写代码的 Agent。

不适用场景

  • 为 CI 设置通过/失败门禁:请使用 fallow audit(失败时会以非零状态码退出)。
  • 查看整个项目的健康状况、清理或死代码报告:请使用 fallow 技能。

人工审查简报速览

# Auto-detect the base (merge-base against the upstream / remote default):
fallow review

# Pin the base, or scope to a precise diff:
fallow review --base origin/main
git diff --find-renames origin/main...HEAD | fallow review --base origin/main --diff-stdin

人工审查简报会显示概况信息、关注地图和决策面(“需要作出的决策”)。--format json 会输出完整的结构化封装(decisions、focus、deltas、impact_closure、partition、graph_facts)。--max-decisions N 可调整上限(限制在较小范围内)。--show-deprioritized 会展开关注地图中折叠的内容。

决策面

每项决策都是一个经过明确表述的问题,并锚定到 fallow 根据图谱确定性推导出的 signal_id(差异键或协同缺口键)。可发布的类别恰有三种:

  • coupling-boundary:新增跨区域依赖边。
  • public-api-contract:新增导出的公共 API 表面,或变更了被此差异之外的模块使用的契约(用于确认或协调的信号)。
  • dependency:变更的 package.json 添加了第三方条目,或将已声明条目升级了一个主版本(或一个 0.x 次版本)。每个清单文件、每种类别各生成一项批处理决策,并根据受影响包在仓库内的导入方数量加权:blast 是导入方数量,internal_consumer_count 是差异之外的导入方数量。两个计数都是批处理中所有包的并集。dependencies 以外的条目会在问题中显示 (dev)、(optional) 或 (peer) 标签。digest.deltas 会将键列为 dependency_added(<manifest>::<name>)和 dependency_major_bumped(<manifest>::<name>@<from>-><to>);这两个列表始终存在,也可能为空。次版本和修订版本升级,以及非数字范围(workspace、file、git、标签)均不会作为候选项。dependency 决策没有 suppress 操作:其锚点是 package.json,该文件无法附带注释,因此绝不要将 // fallow-ignore 行粘贴到清单中。decision_surface MCP 工具会显示与 CLI 相同的依赖项决策。表述规则:引用变更日志问题(“<from> 到 <to> 之间记录的哪项变更会影响这 N 个导入方?”);不要猜测行为变更。

当决策的锚点文件在变更中被重命名时,它可能带有 previous_signal_id:这是同一决策在旧路径下对应的 signal_id,这样审查界面便可以通过 git mv 将先前的审查者评论重新关联起来。

引出更广泛的权衡(品味归属)

上面的决策范围是确定性部分:仅限 fallow 能从图中证明的权衡(三类)。实际的架构权衡范围更广(抽象级别、错误处理策略、数据模型形态、急切与延迟、状态归属、可扩展性与 YAGNI 的取舍、可测试性、信任边界),这些都无法通过图检测。要呈现这些内容,需要模型阅读差异,而不是静态检查。

对差异和指南运行 references/tradeoff-elicitation.md 中的权衡引出提示词。它遵循品味归属原则:模型让每个选择清晰可见,并提出真正开放的问题;由人来决定。提示词包含诚实约定(以差异为依据、observed / tradeoff / question 的划分、deterministic: false 的标记、来源信息、最多五项并诚实弃答、不重复确定性范围,以及 options 绝不替人做选择)。fallow 负责它能证明的内容,提示词覆盖其余部分,而标记可防止两者混淆。

将其作为审查步骤运行

若要在确定性决策旁呈现权衡范围:

  1. 获取指南并阅读差异:
    fallow review --base <ref> --walkthrough-guide --format json > guide.json
    git diff <ref>...HEAD            # or: git diff --cached  for staged work
    
  2. 对差异和 guide.json 运行 references/tradeoff-elicitation.md 提示词。
  3. 保留封装结构({ graph_snapshot_hash, abstained, tradeoffs[] } 形态)。下方的组合审查会用到它。

此步骤刻意不属于下方的验证后 Agent 契约循环。权衡封装绝不会通过 fallow review --walkthrough-file 往返处理(该命令只验证已输出的 signal_id),因此它不具备 fallow 级别的保证:每项内容都保持 deterministic: false,由 Agent 根据差异自行检查,而非通过图验证。不要将其说成已通过 fallow 验证。

Agent-contract 循环

该循环让 Agent 生成判断,再由 fallow 根据实时图谱进行后置验证。验证者是图谱,而不是第二个模型。

  1. 获取指南:

    fallow review --base origin/main --walkthrough-guide --format json > guide.json
    

    指南包含:digest(简述和决策范围)、direction(查找方向)、graph_snapshot_hash(防陈旧校验值)、agent_schema(需要返回的精确结构)以及 injection_note。摘要仅根据图谱构建;PR 文本绝不会被纳入,因此该指南在设计上具有注入抵抗能力。

  2. 阅读 digest 中的决策。每项决策都包含 signal_id、category、拟定的 question,以及 anchor_file / anchor_line。

  3. 返回符合 agent_schema 的判断:

    {
      "graph_snapshot_hash": "<echo the value from the guide>",
      "judgments": [
        {
          "signal_id": "<one signal_id fallow emitted>",
          "framing": "<your reasoning for the human reviewer>",
          "action": "<block | address | consider | fyi>",
          "concern": "<optional: one lens from agent_schema.concern_vocabulary>"
        }
      ]
    }
    

    每个 signal_id 都必须是指南中由 fallow 发出的 ID(emitted_signal_ids)。未锚定的 ID 会被拒绝。原样回传 graph_snapshot_hash。

    对于没有发现问题的变更区域,判断可以引用指南的 change_anchors 中已发出的 change_anchor(chg: ID),代替 signal_id。每个锚点都包含 file、start_line 和 line_count。未知 ID 会被拒绝,并标记为 unknown-change-anchor。

    action 表明该判断要求作者做什么:block 和 address 是必需操作,consider 是可选操作,fyi 则无需采取行动。concern 指明关注维度;优先使用指南的 agent_schema.concern_vocabulary 中的词汇,即 13 个 kebab-case 关注维度:abstraction、coupling、data-model、error-handling、control-flow、performance、dependencies、api-ergonomics、compatibility、state-ownership、extensibility、testability、trust-boundary。指南通过 agent_schema.action_vocabulary 和 agent_schema.concern_vocabulary 发布这两个列表;请从指南读取,而非从本文件读取。action_vocabulary 会强制执行;concern_vocabulary 仅供参考,接受任意字符串。

  4. 后置验证:

    fallow review --base origin/main --walkthrough-file judgment.json --format json
    

    响应会将每项判断分类为:

    • accepted:signal_id 已发出,且快照匹配;Agent 的 framing 会标记为非确定性内容(deterministic: false),绝不会作为门槛。action 会与 agent_framing 一同回传,并以相同方式标记:它是给作者的指示,而非 fallow 事实。
    • rejected,且 reason: "unanchored-signal-id":signal_id 从未发出(属于幻觉)。请删除或修正。
    • rejected,且 reason: "invalid-action" 和 invalid_value(fallow 拒绝的标签):action 不在词汇表中。只有在锚点解析成功后才会报告此错误;如果锚点是幻觉,且标签也无效,则会改为以 unanchored-signal-id / unknown-change-anchor 拒绝。先修正锚点,再修正标签。
    • rejected,且 reason: "stale-snapshot" 和 stale: true:自获取指南以来,代码树已发生变化。请重新获取指南并重新作出判断。

生产运行时数据(Fallow Cloud)

当项目向 Fallow Cloud 发送生产覆盖率数据时,请据此检查变更函数。使用范围限定的读取,而不是完整的运行时上下文拉取:

  • 编辑之前: fallow coverage review-packet --repo <owner/repo> --base <ref>(MCP:get_cloud_review_packet)。读取 hit_count、covered_by_test,以及有提供时的调用方信息。covered_by_test: null 的高热度函数属于高风险编辑。
  • 删除之前: 必须确认该时间段内的 period_tracking_state: "never_called",不能只看 tracking_state,并读取 evidence_window.observed_hours。观测时长较短或低流量界面意味着“未访问”,而非“已失效”。
  • 部署之后: fallow coverage deployment-changes --repo <owner/repo>(MCP:get_cloud_deployment_changes)。当 comparable 为 false 时,报告 reason,并且不得声称发生了变化。
  • 根据 repo_path 打开文件,而不是 file_path。

这些数据仅作上下文:在 framing 中引用,绝不可作为门槛。字段含义和完整流程:references/production-runtime-data.md。

撰写审查意见

验证不是评审。接受各项判断后,请按此固定顺序呈现给读者,让他们先看到会影响结果的内容,最后看到确定性的剩余项:

  1. 已接受的决策判断,按 direction.order 排列。每项都逐字保留摘要中的 question 和 tradeoff,接着给出你的 framing,然后给出体现其权重的数值:internal_consumer_count、out_of_diff 路径,或该单元的 scoring_budget。
  2. 权衡项,取自征询步骤,按 consequence 排序,最多五项。当信封为 abstained: true 时,打印一行说明此情况;不要填充此项。
  3. 扣除项:用一行列出简报中的计数:“已确定性处理:N 个死代码、N 个重复项、N 个复杂度问题、N 个样式问题;不在讨论范围内”。绝不要根据差异重新计算其中任何一项;这些数据以简报为准。
  4. 降低优先级的项目:用一行列出数量,并注明可通过 --show-deprioritized 查看,这样既不会隐藏内容,也不会凑数。
  5. 没有决策且权衡项信封为已弃答的评审,仍是完整评审:“没有实质性影响;确定性发现:N”。这不是失败,也绝不是编造项目的理由。

三个图事实会影响评审内容。只有 test_reach 注记可以添加项目,且它必须锚定在 change_anchor 上:

  • 每个方向单元都带有 test_adjacency:none(没有测试文件导入此单元)、untouched(存在导入它的测试文件,但不在差异中),或 changed(导入它的测试文件在差异中)。测试文件以及未保留图时不会提供此字段。对于 review-here 单元,如果值为 none,请在 framing 中询问作者如何验证。绝不要声称有覆盖;该值只表示测试是否导入此单元,并不表示测试是否执行了这项变更。
  • digest.test_reach 给出每个已更改值导出的覆盖范围。status 为 measured 或 no-tests。counts 包含所有类别。exports 仅列出类别不是 direct 或 framework 的行,每行包含 file、export_name、line 和 reach:
    • transitive:某项测试覆盖了该导出,但没有测试直接指定它。
    • mocked-only:测试用模拟对象替换了该文件(mocked_targets),因此实际代码不会运行。
    • none:某项测试覆盖了该文件,但没有测试覆盖该导出。
    • none-file:没有测试覆盖该文件。 test_reach 请遵循以下规则:
    • 缺失表示没有事实。较早的 fallow 版本不会输出此字段;当没有值导出发生变化时,此字段也会缺失。此时使用 test_adjacency。
    • 对于文件中有 mocked-only、none 或 none-file 行的 review-here 单元,请引用该行(文件、导出项、类别)。询问作者如何验证。
    • 行中没有 signal_id。请将备注锚定在同一 file 中、范围与导出声明重叠的 change_anchor 上。如果没有重叠的锚点,则使用该文件中的第一个锚点。如果存在针对该文件的决策,请将备注写入其说明中。
    • 当 test_reach 与 test_adjacency 不一致时,使用 test_reach,因为它针对每个导出项,且能识别模拟对象。
    • 绝不要根据这些事实写“已测试”或“已覆盖”。direct 表示测试中点名了该导出项,不表示测试运行了发生变化的代码行。
    • reach 集合是开放的。遇到未知值时需要留意。
    • 当 exports_omitted 大于 0 时,列表不完整。某个文件没有对应行,并不能证明其 reach 为 direct。请使用 counts。
    • 对于 status: "no-tests",写一条概述说明,而不是每个导出项各写一条。
    • 对于 masking: "capped",图无法识别模拟对象。没有 mocked-only 行并不能证明任何事情。
    • 端到端测试不会导入文件。在有端到端测试运行器的项目中,none-file 行仍可能对应端到端测试。请询问,不要妄下结论。
  • digest.partition.independent_slices 列出单元间依赖图的连通分量,每项都是按排序排列的模块目录列表。仅当存在两个或更多切片时才会提供此字段;缺失表示此变更是一个连通整体。当 digest.triage.risk_class 为 high 且该字段存在时,请将其作为概述事实指出:“此变更沿着图证明的边界拆分为 K 个独立切片”。这绝不是要求拆分;是否拆分由作者决定。

两条规则决定行文。优先把握整体:一个结构性决策加十条简短备注,意味着该决策本身就是评审;这些备注可附在其下,也可以不写。用数字,不用形容词:每段 framing 都至少引用指南中的一个数字或路径(消费者数量、差异范围之外的路径、scoring_budget)。“可能会很慢”不算发现;“被 14 个模块导入,其中 9 个在此次差异范围之外”才算。

人在回路中的演练(终端)

上面的 agent-contract 循环承载 AGENT 的框架。同一个循环也承载 HUMAN 的裁定,并提供相同的、经图验证的反幻觉保证,因此终端审阅者可以留下能追溯锚点并往返传递的备注。该契约使用现有的 --walkthrough-guide / --walkthrough-file 往返流程,而非新增接口。

人类负责判断好坏;你只负责传递备注。fallow 验证的是 ANCHOR(信号或变更区域确实存在),而非备注是否正确;每条传递的备注都保持 deterministic: false,且绝不作为门槛。

  1. 呈现演练内容并查看锚点:

    fallow review --base origin/main --walkthrough                       # the staged human tour
    fallow review --base origin/main --walkthrough-guide --format json > guide.json
    

    guide.json 包含决策 signal_id(框定的结构性问题)、每个变更区域对应的 change_anchors 集合(每项为 { "change_anchor": "chg:<hex>", "file", "start_line", "line_count" }),以及用于检测过时状态的 graph_snapshot_hash 固定值。向人类展示演练内容,并针对其选择标记的每一项,收集简短的裁定 / 备注,以及他们希望作者采取的行动。仅提供四种标签(block、address、consider、fyi);未知标签将被拒绝,并返回 invalid-action。

  2. 将每条人类备注作为判断传递(原样回显哈希;引用 fallow 针对已标记决策发出的 signal_id,或引用人类备注所涉及的其他任何变更区域的 change_anchor;将人类的行动作为 action 传递):

    {
      "graph_snapshot_hash": "<echo from guide.json>",
      "judgments": [
        { "signal_id": "<an emitted decision signal>", "framing": "<the human's verdict/note>", "action": "address", "concern": "<optional>" },
        { "change_anchor": "<an emitted chg: id>", "framing": "<the human's note on this region>", "action": "consider", "concern": "<optional>" }
      ]
    }
    
  3. 验证采集结果:

    fallow review --base origin/main --walkthrough-file judgment.json --format json
    

    响应的排序方式与 agent-contract 循环相同,另有两项变化:accepted 包含 anchor_kind("signal" 或 "change"),且 fallow 从未发出的 change_anchor 会被拒绝,并返回 unknown-change-anchor。请重新锚定到真实信号或区域;不要编造锚点。

  4. 采取行动: 将已接受的人类裁定转交给编码会话。传递每条备注的 action,以便接收方 Agent 进行分类处理:block 和 address 必须处理,consider 可选处理,fyi 无需更改。备注带有锚点和限制,不会被当作 fallow 级别的事实。

保证:人类无法将备注锚定到 fallow 未发出的信号或区域;如果备注针对的代码树已发生变化,备注会被拒绝,而不会被悄然错配。

此循环会拒绝的合理化说辞

合理化说辞实际情况
“我在差异中看到了死代码,马上标出来”Subtract 已负责此事;再次推导只会制造噪声,也可能出错。请转达简报中的计数。
“这个 signal_id 看起来没问题”只有 emitted_signal_ids 才存在。其他任何值都是幻觉,fallow 会以 unanchored-signal-id 拒绝。
“目标是五个权衡项”五个是上限。abstained: true 且列表为空,也是有效完整的答案。
“问题是开放式的,我就直接提一下修复方案”指定修复方案是在开处方。请重新表述为开放式决策,或列出两个及以上确有成本的选项。
“代码树只变了一点,演练指南应该还没问题”它已是 stale-snapshot。请重新获取指南并重新作出判断。
“测试通过了,所以改动没问题”测试通过是验证事实,并非对决策面的裁定。仍需人类对这些决策作出判断。
“有测试导入这个文件,所以它经过了测试”test_adjacency 只检查导入关系。mocked-only、none 或 none-file 行表示没有测试通过导入触及真实导出。请询问验证方案。
“生产环境从未调用它,所以删掉吧”请检查 period_tracking_state 和 evidence_window.observed_hours。观察窗口较短或路径罕见,意味着“未访问”,而不是“已废弃”。

备注

  • review 是 audit --brief 的别名;--format 与简报相互独立。
  • 全项目分析请参阅 fallow 技能;完整标志列表请参阅其 references/cli-reference.md。

评论

支持 Markdown