
🎯 学 gstack 的审查状态追踪系统:不是一次性的"审完就忘",而是持久化每次审查的结果——跨审查去重、审查状态可见、/ship 集成,让审查成为工程流程中持续可见的一环。 ⏱️ 预计时间:25 分钟
[!quote]- 📖 原Skill精要 技能名称:review-dashboard([[L6-15-PR代码审查|review]] 的子系统) 核心功能:gstack review 的持久化审查状态追踪系统。每次审查结果通过
gstack-review-log写入结构化日志(JSONL),包含质量评分、专家统计、发现详情、修复操作。跨审查去重(指纹比对),审查状态对 [[L6-25-发布上线管理|ship]] 可见,趋势可追踪——让审查成为工程流程中持续可见的一环。 所属体系:gstack 虚拟工程团队 协作关系:[[L6-25-发布上线管理|ship]] 读取审查日志以确保未审查分支不能发布
1. 课程概览
💡 白话小课堂:传统 code review 就像在沙子上写字——潮水一来就不见了。审查完了之后:你记得审了什么吗?哪些发现被修复了?哪些被跳过了?之前跳过的发现在新提交中又出现了吗?/ship 知道这个分支审过了吗?审查仪表盘回答所有这些"审查之后"的问题。它把每次审查结果持久化为 JSONL(一种既机器可读又人类可读的格式),支持跨审查去重(同一个问题如果上次被 skip 了、代码没变,这次自动抑制),在计划文件中显示审查进度表格(像作战地图上的情报),并且 /ship 合入前会检查——至少有一次审查完成、最后一次 clean、Quality Score 达标,否则阻止合入。
2. 审查仪表盘解决什么问题?
传统审查的"不可见"问题
一次代码审查完成后: → 你记得审了什么吗?(一天后?一周后?) → 哪些发现被修复了?哪些被跳过了? → 之前审查中跳过的发现在新提交中仍然存在吗? → /ship 知道这个分支已经审过了吗? → 跨审查的趋势是什么?代码在改善还是恶化?
gstack 的审查仪表盘(Review Readiness Dashboard)回答所有这些问题。 它把审查从"一次性事件"变成"持续可见的工程状态"。
核心能力:
- 持久化审查结果 → /ship 集成
- 跨审查发现去重 → 不再重复问同一问题
- 审查状态报告 → 一眼看到分支的审查覆盖情况
- Plan mode 集成 → 计划文件中显示审查进度
3. 审查结果持久化:gstack-review-log
gstack-review-log 记录什么
每次 /review 完成后,持久化一个 JSON 条目:
{ "skill": "review", "timestamp": "2026-05-03T14:30:00Z", "status": "clean" | "issues_found", "issues_found": N, // 剩余未解决发现总数 "critical": N, // 剩余未解决关键发现 "informational": N, // 剩余未解决信息发现 "quality_score": 7.5, // PR 质量评分(0-10) "specialists": { // 每个专家的结果 "testing": {"dispatched": true, "findings": 2, "critical": 0, "informational": 2}, "security": {"dispatched": false, "reason": "scope"}, ... }, "findings": [ // 每个发现的结果 {"fingerprint": "app/models/user.rb:42:race-condition", "severity": "CRITICAL", "action": "fixed"}, {"fingerprint": "lib/utils.rb:18:magic-number", "severity": "INFORMATIONAL", "action": "auto-fixed"}, {"fingerprint": "config/routes.rb:10:enum-completeness", "severity": "CRITICAL", "action": "skipped"} ], "commit": "a1b2c3d" }
status 字段的含义
→ "clean" — 处理后没有剩余未解决的发现 → "issues_found" — 仍有未解决的发现(跳过的或需要后续跟踪的)
findings 中 action 的含义
→ "auto-fixed" — Agent 在 Step 5b 中自动修复 → "fixed" — 用户在 Step 5d 中批准修复 → "skipped" — 用户选择跳过此发现(下次审查可抑制)
4. 审查结果读取:gstack-review-read
gstack-review-read 返回什么
该命令读取当前分支的所有审查条目,返回:
→ 每次审查的摘要行: [TIMESTAMP] | STATUS | CRITICAL N | INFORMATIONAL N | QUALITY X/10 → 每次审查中每个发现的指纹和行动 → 配置信息(用于解析的元数据)
典型输出示例
2026-05-03T14:30:00Z | clean | 0 | 0 | 9.0 {"fingerprint":"app/models/user.rb:42:race-condition","severity":"CRITICAL","action":"fixed"} {"fingerprint":"lib/utils.rb:18:magic-number","severity":"INFORMATIONAL","action":"auto-fixed"} ... ---CONFIG--- slug: myproject reviews_path: ~/.gstack/projects/myproject/main-reviews.jsonl ---HEAD---
解析规则:
→ ---CONFIG--- 之前的是 JSONL 条目
→ ---CONFIG--- 和 ---HEAD--- 之间的不是 JSONL
5. 跨审查发现去重
为什么要去重?
场景: 第 1 次审查 → 用户选择 skip 发现 A 第 2 次审查 → 代码没变 → 又标记了发现 A → 浪费:用户再次看到同样的问题,再做同样的选择 → 伤害信任:感觉 Agent 不记得上次说过什么
去重算法(Step 5.0)
- 运行 gstack-review-read 获取之前审查的 skip 发现
- 收集所有 action="skipped" 的指纹
- 获取 skip 发现所在审查的 commit SHA
- 运行 git diff --name-only HEAD 获取变更文件
- 对当前审查的每个发现: → 指纹匹配之前 skip 的发现? → 发现的文件不在变更文件列表中? → 两个条件都满足 → 抑制该发现
去重的边界条件
→ 只抑制"skipped"的发现——"fixed"或"auto-fixed"的不抑制 (因为修复可能已被回退或代码变更导致了回归) → 文件变更了 → 不抑制(代码改了,需要重新评估) → 只检查当前分支的审查历史
🔑 核心秘诀:跨审查去重的关键是"只抑制 skipped,不抑制 fixed"。
6. 计划文件集成——审查状态在计划中可见
Plan Status Footer
在计划模式中,如果计划文件没有 ## GSTACK REVIEW REPORT 章节: → 运行 gstack-review-read → 追加标准表格:
| Review Run | Status | Critical | Informational | Quality | Commit |
|---|---|---|---|---|---|
| 2026-05-03T14:30:00Z | clean | 0 | 0 | 9.0 | a1b2c3d |
如果无审查或空结果 → 5 行占位表格,裁定: "NO REVIEWS YET — run /autoplan"
为什么放在计划文件中?
→ 计划是分支的"作战地图" → 审查状态是作战地图上的关键情报 → 一个文件看到所有信息:要做什么 + 做完了吗 + 审过了吗 → 对多会话、多天的工程工作至关重要
7. /ship 集成——ship 知道你审过了
/ship 如何读取审查状态
/ship 在合入前会:
- 运行 gstack-review-read
- 检查是否至少有一次审查完成
- 检查最后一次审查的状态: → "clean" → 继续 ship 流程 → "issues_found" → 展示剩余问题列表 → 无审查记录 → 提示先运行 /review 或 /autoplan
为什么 /ship 需要审查状态?
→ 防止"忘了审就合"——代码未经审查就进入主分支 → 确保"审过的问题都处理了"——不是审了就完,是审了且修复了 → 提供审计追踪——"谁审的、什么时候、结果如何"
8. 审查仪表盘的设计哲学
不是"报告",是"状态机"
传统审查工具:生成一份报告 → 人读 → 决定 → 忘了
gstack 审查仪表盘:持久化状态 → Agent 读 → 决策自动化 → 持续可见
核心设计原则:
- 机器可读优先——JSONL 格式,Agent 可以直接解析
- 增量累积——每次审查追加,不是覆盖
- 去重内建——不重复劳动
- 跨工具可见——/review 写入,/ship 读取,计划文件展示
- 分支级作用域——每个分支的审查状态独立
与其他 gstack 系统的协同
→ /review:写入审查结果 → /ship:读取审查状态作为合入门控 → /autoplan:自动触发审查,仪表盘汇总所有审查 pass → Plan Mode:在计划文件中实时展示审查进度 → /retro:跨项目汇总审查趋势(quality_score 的时间序列)
9. 结构拆解:审查仪表盘 Skill 模板
审查状态追踪型 Skill 模板
核心特征
→ 管理对象 = 审查结果的持久化、检索、去重和跨工具共享——审查的"记忆系统" → 核心原则 = 状态机模式(非一次性报告)+ 机器可读优先(JSONL)+ 增量累积(追加非覆盖) → 关键设计 = gstack-review-log JSONL 持久化、跨审查指纹去重、 Plan Status Footer 集成、/ship 门控读取、分支级作用域
通用结构
Review Log Persistence(审查日志持久化)
- 格式:JSONL(每行独立 JSON 对象,增量追加)
- 字段:status / critical / informational / quality_score / specialists / findings / commit
- action 类型:auto-fixed / fixed / skipped
- 分支级作用域:每个分支的审查状态独立存储
Cross-Review Dedup(跨审查去重)
- 读取之前审查中 action="skipped" 的指纹
- 条件:指纹匹配 + 文件未变更 → 抑制
- 边界:只抑制 skipped(fixed/auto-fixed 不抑制,修复可能被回退)
- 仅检查当前分支审查历史
Cross-Tool Visibility(跨工具可见性)
- /review → 写入审查结果
- /ship → 读取审查状态作为合入门控
- Plan Mode → ## GSTACK REVIEW REPORT 表格
- /autoplan → 触发审查,仪表盘汇总
- /retro → 跨项目 quality_score 时间序列趋势
Design Philosophy(设计哲学)
- 机器可读优先(Agent 直接解析 JSONL)
- 增量累积(追加,不覆盖)
- 去重内建(不重复劳动)
- 状态机模式(非一次性报告,持续可见)
10. 电商 Skill 案例:审查仪表盘——追踪双 11 准备期的代码质量
🛒 实战案例:双11前30天,某电商平台进入封网期(只修bug、不上新功能)。CTO需要确保所有合入的hotfix都经过审查、代码质量不因紧急修复而下降、且5个Squad(交易/商品/支付/商家/增长)的审查状态透明可见。部署了review-dashboard作为封网期的质量追踪中枢。
- 全景仪表盘:封网期(10/12-11/11)总PR数47,已审查47(100%),Clean 41(87%),Issues Found 6(13%已全部修复),平均Quality Score 8.2/10,趋势7.5→8.2(+0.7)。按Squad拆分——交易18PR Quality 8.5上升、商品12PR Quality 8.8稳定、支付8PR Quality 7.2(⚠️接近阈值7.0)、商家5PR Quality 8.0、增长4PR Quality 7.5上升。CTO每天早9点扫一眼仪表盘就看到风险点。
- 多次审查追踪案例:
hotfix/double11-payment-callback-timeout分支的完整生命周期——第1次审查(10/28 14:30) Status: issues_found, CRITICAL 2个(回调幂等性缺失、超时未处理), INFORMATIONAL 3个, Quality 3.5/10→需要修复;第2次审查(10/28 16:15) CRITICAL 1个剩余(签名算法仍不正确), INFORMATIONAL 1个, Quality 6.5/10。跨审查去重生效:第1次审查中skip的"魔数5000"(已确认是微信API标准超时值)→抑制;第3次审查(10/28 17:45) Status: clean, Quality 9.0/10→可以合入。Quality从3.5→6.5→9.0每次审查改善2.75分。- 跨审查去重的实际价值:无去重时总计标记11次(含3次重复讨论已知已处理的问题),有去重后仅标记6次(抑制了第2次和第3次审查中的已知skip项,只标记有实质意义的新发现)。节省了工程师3次不必要的"这个我们上次讨论过了"的沟通成本。
- /ship门禁集成:仪表盘与发布系统集成——/ship检查审查状态时,如果目标commit的Quality Score < 7.0或仍有未解决的CRITICAL,拒绝发布。封网期间发生过1次拦截:hotfix #3(CDN缓存预热)第1次审查Quality 4.0,/ship被拦截→修复后重新审查Quality 8.0→放行。"审查仪表盘是/ship的底层数据源——它保证了'没有审查过的代码不能上生产'"。
封网期结束后复盘:30天内0个线上事故源于代码质量问题(仅1次CDN缓存配置失误但非代码bug),对比去年同期封网期线上事故3次——review-dashboard功不可没。
🔑 启示:审查仪表盘的真正价值不是"看着好看的数据面板"——是让质量异常可见。支付Squad Quality 7.2的橙色警告让CTO提前介入,而不是等到双11当晚支付模块挂了才发现质量下滑。
/ship hotfix/double11-payment-callback-timeout
Step 3: 审查状态检查
→ gstack-review-read → 发现 3 次审查记录
→ 最后一次状态: clean
→ Quality: 9.0/10
门控检查:
✓ 至少一次审查完成
✓ 最后一次审查 clean
✓ Quality >= 7.0(封网期阈值,日常是 5.0)
✓ 所有 CRITICAL 已修复
→ 通过 ✓ → 继续 ship 流程
如果无审查记录 → /ship 会阻止:
"No reviews found. Run /review or /autoplan first."
封网期结束后——数据汇总
封网期审查总结(/retro 数据源之一):
总审查次数: 62 次(47 个 PR,15 个需要多次审查)
平均审查次数/PR: 1.32 次
→ 大部分 PR 一次通过(68%)
→ 需要多次审查的主要是支付 Squad(安全审查严格)
发现统计:
CRITICAL 发现: 28 个(平均 0.6 个/PR)
INFORMATIONAL 发现: 94 个(平均 2.0 个/PR)
AUTO-FIX: 67 个(71% 的 INFORMATIONAL 自动修复)
跨审查去重节省:
→ 抑制了 23 个重复问题
→ 节省了约 46 分钟的无效审查时间(每次审查 2 分钟思考)
Quality Score 趋势:
封网期开始时: 7.5 → 结束时: 8.2 → +0.7 提升
说明:只修 bug 的时期,代码质量反而提高了
(因为没有新功能引入新的复杂度)
⚠️ 避坑指南: Quality Score 从 7.5 升到 8.2 在封网期是有趣的信号——说明"只修 bug"时代码质量反而提高了。这是因为新功能是代码质量的最大敌人(新功能 = 新复杂度 = 新 bug)。
11. 掌握检验
Q1:审查仪表盘将审查结果持久化为 JSONL 格式而非关系数据库的原因是什么?
- A) JSONL 更美观
- B) JSONL 既可机器解析也可人类直接阅读,且增量追加无需迁移
- C) 关系数据库不支持跨审查去重
- D) gstack 不支持任何数据库
Q2:跨审查去重中,为什么"skipped"的发现被抑制而"fixed"的不被抑制?
- A) skipped 是严重的 bug,必须追踪
- B) skipped 是有意不修的(代码未变无需再问),fixed 的修复可能已被回退需重新评估
- C) 这只是设计习惯,没有深层原因
- D) fixed 的发现更重要
Q3:在双 11 封网期案例中,支付 Squad 的 Quality Score 只有 7.2(接近阈值 7.0)。假设你是 CTO,请基于审查仪表盘的数据,提出至少 3 个具体的诊断问题来确定支付 Squad 的质量风险是"暂时性的"还是"系统性的"。
Q4:计划文件中 ## GSTACK REVIEW REPORT 表格的设计哲学是"在作战地图上标注情报"。请解释为什么把审查状态放在计划文件里(而非单独的仪表盘页面)对多天、多会话的工程工作至关重要?
Q5:封网期结束后 Quality Score 从 7.5 升到 8.2(+0.7)。课程中说"新功能是代码质量的最大敌人"。请分析:如果你是 CTO,这个洞察会让你如何调整正常迭代期的工程实践?
Q6:审查仪表盘的"机器可读优先"原则和"/ship 门控集成"共同构成了什么架构模式?如果审查状态只有人类可读的 HTML 报告而没有 JSONL——当 /ship 试图自动判断"这个分支是否允许合入"时——会面临什么具体的工程挑战?请从解析可靠性、格式演化、工具解耦三个角度分析。
12. 答案
点击查看答案
Q1:B —— JSONL 兼具机器可解析和人类可阅读性,每行是独立的 JSON 对象意味着增量追加只需 append 一行,无需数据库迁移、schema 变更或连接管理。
Q2:B —— skipped 表示"我看了但决定不修"——如果代码没变,这个问题不需要再讨论。
Q3:三个诊断问题:①最近 5 次审查中 CRITICAL 发现的类型是否相同?(如果同是"支付回调签名"问题反复出现 → 系统性;如果每次是不同的新问题 → 可能是复杂领域的正常探索)②支付 Squad 与其他 Squad 的 Review 次数/PR 比是多少?(如果高 → 说明代码反复被退回,技能问题)③查看每次审查后 Quality Score 是从什么起点涨到 7.2 的?(如果都是从 3-5 分修上来的 → 初次提交质量差;如果初分数就接近 7 → 安全门槛高导致的低分是常态)。
Q4:开发者在多天工作中频繁切换上下文——上午在 PR-A,下午在 PR-B,回到 PR-A 时已经不记得上次审查状态。如果审查状态表格就在计划文件里(同一页),开发者不需要切换工具就能看到"上次审出了 2 个 CRITICAL,都修了吗?"——上下文切换成本为 0。如果审查状态在单独页面,开发者需要"记得去查"——而人是不可靠的。放在作战地图上 = 信息在决策点就位,而非需要主动寻找。
Q5:三个实践调整:①分阶段迭代——把大功能拆成最小可交付单元,每个单元单独审查、单独合入、单独监控质量分数变化,发现质量下降立即停止新功能交付;②设置 Quality Score 底线——正常迭代期如果 Score 连续 3 次下降触发"功能新增冻结",只允许修复类 PR 直到 Score 回升;③复现封网期的"只修 bug"节奏——每月安排一周"质量周",不做新功能只修 bug 和优化,让质量曲线像封网期一样自然回升。
Q6:"机器可读优先"和"/ship 门控集成"共同构成了自动决策管道(Automated Decision Pipeline)模式——数据生产方(review)以结构化契约(JSONL schema)写入状态,数据消费方(ship)无需人工解读直接读取并做出自动化决策。如果只有 HTML 报告:(1) 解析可靠性——/ship 需要一个 HTML 解析器从报告中提取 quality_score 和 status,一个 CSS class 名或 DOM 结构的变化就会破坏解析,导致合入门控失效(最危险的是静默失效——解析器返回 undefined 被当作"通过");(2) 格式演化——HTML 报告的设计会随着视觉需求变化(加图表、改布局、增删列),每次格式变化都需要同步更新解析器,生产和消费高度耦合;(3) 工具解耦——JSONL 的 schema 是显式契约,review 和 ship 之间通过契约而非实现耦合。如果格式变了但字段不变(如 JSONL 增加新字段),ship 无需任何修改即可继续工作。HTML 没有这种契约——任何渲染层的改动都可能破坏下游消费。
(5/6 通过)
(4/5 通过)
延伸阅读
- [[L6-15-PR代码审查|PR代码审查 —— AI帮你把关每一行代码的质量]]
- [[L6-17-审查清单体系|审查清单体系 —— 让代码审查像飞行员起飞前检查一样可靠]]
- [[L6-19-外部AI评论分诊|外部AI评论智能分诊 —— 过滤噪音、保留真问题]]

评论区
共 0 条评论