ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

GSD-Core 修复 `total_phases` 误计:非阶段章节标题不再污染里程碑阶段计数

2026/9/25 15:02:18 拓冰建站 浏览量
GSD-Core 修复 `total_phases` 误计:非阶段章节标题不再污染里程碑阶段计数 【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载本篇文章聚焦 GSD-Core 中一个极具代表性的计数一致性修复changeset #549当 ROADMAP.md 中出现形如## Phase Overview:的非阶段章节标题时STATE.md 的progress.total_phases会被多计 1。文章将还原该 Bug 的完整根因链解析digit-anchored 阶段标题模式与单一事实源single source of truth的修复思路并通过仓库源码与回归测试展示如何在实践中验证与规避同类问题。读完本文你将掌握 GSD-Core 阶段计数体系的底层原理以及如何用gsd-tools roadmap analyze/state json/state sync交叉核验阶段总数的正确性。背景progress.total_phases在 GSD-Core 中的地位在 GSD-Core 的规划工作区中每个里程碑的进度由.planning/STATE.md前端的progress嵌套块承载核心字段为total_phases/completed_phases/percent。根据 docs/reference/state-md.md 的字段表字段类型说明progress.total_phasesinteger当前里程碑中的阶段总数从 ROADMAP.md 与阶段目录派生progress.completed_phasesinteger已完成的阶段数progress.percentinteger 0–100阶段维度下的里程碑进度min(completed_plans/total_plans, completed_phases/total_phases)total_phases不仅仅是一个展示数字它是状态行进度条hooks/gsd-statusline.js 中读取completed_phases / total_phases / percent渲染进度条、percent计算、乃至里程碑完成判定percent为 100 或completed_phases total_phases的分母。一旦total_phases被虚增整个里程碑的完成度会被系统性低估——这正是 bug #549 的危险之处它不是崩溃而是一个看起来完全正常的错误进度。Bug #549 的根因宽松正则把章节标题当成了阶段宽松匹配模式getMilestonePhaseFilter根因位于getMilestonePhaseFiltersrc/roadmap-parser.cts L1898。该函数是里程碑阶段过滤的唯一所有者负责从 ROADMAP.md 的当前里程碑窗口中提取本里程碑声明了哪些阶段。其内部使用的阶段标题匹配模式为#{2,4}\s*Phase\s([\w][\w.-]*)\s*:这个正则的问题在于[\w][\w.-]*会贪婪地捕获Phase之后的任意单词字符。于是以下这些本意是章节导航的标题## Phase Overview: ## Phase Details:会分别被解析出 tokenOverview、Details并作为阶段被塞入milestonePhaseNums集合——每个这样的标题都会让phaseCount虚增 1。回归测试的注释tests/roadmap.test.cjs L3446-L3450对此有精确描述。计数被错误消费修复前的buildStateFrontmatterSTATE.md 前端信息构建器负责state json读路径将total_phases直接取自getMilestonePhaseFilter.phaseCount。这意味着只要 ROADMAP 里有一个## Phase Overview:这样的导航标题STATE.md 的total_phases就会比真实阶段数多 1。对比之下roadmap.analyze命令src/roadmap.cts 输出phase_count一直使用更严格的 digit-anchored 模式#{2,4}\s*Phase\s(\d[A-Z]?(?:\.\d)*)\s*:\s*([^\n])该模式要求Phase之后必须以数字开头因此只统计真实的阶段标题如### Phase 01:、### Phase 05.1:天然排除Overview/Details这类纯单词标题。结果便是同一份 ROADMAP 出现了两个互相矛盾的阶段总数roadmap analyze报告 7而state json/state sync报告 8。这正是变更集 .changeset/archived/549-total-phases-decimal-overcounting.md 所修复的分歧。修复方案共享同一个 digit-anchored 计数源修复的核心原则单一事实源变更集的修复描述非常简洁而明确BothbuildStateFrontmatterandcmdStateSyncnow sourcetotal_phasesfrom the same digit-anchored phase-heading pattern used byroadmap.analyze— single source of truth.翻译过来就是所有需要统计ROADMAP 声明了多少阶段的地方都必须走同一个 digit-anchored 标题模式而不是各自维护一套正则。两份实现之间的任何细微差异都会演变成读路径与写路径互相矛盾的隐性 Bug。落地实现countRoadmapPhaseHeadings修复在 src/state.cts 中落地为一个共享辅助函数countRoadmapPhaseHeadingsL2722-L2769。它同时被两条路径复用读路径buildStateFrontmattersrc/state.cts L2776在 L2998-L3000 处调用它计算roadmapPhaseCount写路径cmdStateSyncsrc/state.cts L6004在 L6149-L6153 处用同一份计数决定syncTotalPhases。该函数的关键判据是数字存在性检查// Only count tokens that contain at least one digit — excludes // pure-word section headings (Overview, Details) while keeping // numeric phases (01, 05.1) and project-code IDs (PROJ-42). if (!/\d/.test(token)) continue;这一行是整个修复的灵魂它既不要求 token 必须是纯数字也不对Phase之后的单词形式做过度限制而是用必须包含至少一个数字这一最小约束把Overview、Details这类纯单词章节标题排除在外同时完整保留整数阶段01、02、06十进制插入阶段05.1GSD-Core 支持在阶段间插入小数编号的热修复阶段项目代码前缀 IDPROJ-42在启用 milestone-prefixed / 项目代码约定时。同时该函数沿用了此前的成熟规则跳过 fenced 代码块内的标题tokenizeHeadings的 fence 感知、排除999.x冰盒icebox阶段、排除已退役struck-through阶段——这些都是同一计数点长期演进的成果详见下文演进脉络。修复后的行为对比以回归测试的夹具tests/roadmap.test.cjs L3479-L3505为例ROADMAP 包含## Milestone v1.0: Test Milestone ## Phase Overview: ← 非阶段章节标题Bug 触发器 ### Phase 01: Alpha ### Phase 02: Beta ### Phase 03: Gamma ### Phase 04: Delta ### Phase 05: Epsilon ### Phase 05.1: Inserted Hotfix (INSERTED) ← 插入的十进制阶段 ### Phase 06: Zeta真实阶段数为76 个整数阶段 1 个十进制插入阶段。修复前后对比如下来源修复前修复后roadmap analyze的phase_count77state json的progress.total_phases87 1 个Overviewtoken7state sync写入的total_phases87回归测试把 Bug 钉死在测试里修复不是靠嘴说的——仓库在 tests/roadmap.test.cjs L3432 起完整保留了本次 Bug 的回归测试原独立文件tests/bug-549-total-phases-overcounts-with-phase-section-heading.test.cjs在整合 epic #1969 中被折叠进roadmap.test.cjs。测试夹具会真实地搭建一个临时项目写入包含## Phase Overview:的 ROADMAP.md写入带milestone: v1.0的 STATE.md在.planning/phases/下创建 7 个阶段目录01-alpha…06-zeta含05.1-inserted-hotfix。随后跑两条断言state json断言L3558-L3586roadmap analyze的phase_count必须为 7state json的progress.total_phases必须为 7且两者必须严格相等——即读路径必须与权威计数一致。state sync断言L3588-L3608先给 STATE.md 主体加上Progress:字段触发cmdStateSync重写再通过state json验证同步后写入的total_phases仍为 7。这套测试从读路径与写路径两个方向同时锁定契约无论用户用state json读取还是用state sync重写total_phases都必须等于roadmap analyze的phase_count。任何一方重新引入宽松匹配测试都会立即失败。演进脉络同一计数点的系列加固bug #549 并不是孤例。从 CHANGELOG 与源码注释可以看到total_phases的计数精度经历过一系列相邻修复它们共同塑造了今天countRoadmapPhaseHeadings的形态#875 / #880getMilestonePhaseFilter排除 fenced 代码块内的### Phase N:标题避免文档中的示例代码被计为真实阶段#1445 / #1446排除999.x冰盒阶段并允许total_phases向下修正此前进度棘轮会冻结已偏高的计数#2554修正十进制阶段目录如00.1被归一化吞噬的问题——00.1是真实阶段而非里程碑 0#3185规范哨兵谓词sentinel predicate并明确^0\b窄规则与十进制 ID 的取舍边界#549本文统一读/写路径与roadmap.analyze的 digit-anchored 计数模式。这些修复的共同主题只有一个ROADMAP 声明了多少阶段这件事必须有一个且只有一个精确的答案。任何允许另一份正则碰巧匹配出不同数字的实现都是潜在的数据完整性缺陷。实践建议与验证方法保持 ROADMAP 阶段标题的规范格式为避免触发同类问题建议遵循以下约定阶段标题使用数字开头的编号如### Phase 01: Alpha、### Phase 05.1: Hotfix章节导航标题避免使用Phase加单词再加冒号的形态如## Phase Overview:可改用## Overview或不带冒号的措辞若必须保留## Phase Overview:这类标题请确保计数逻辑如本文的/\d/判据能够正确排除纯单词 token。用 CLI 命令交叉核验GSD-Core 提供三条命令形成完整的核验闭环# 1. 权威阶段数digit-anchored 模式统计 gsd-tools roadmap analyze # 2. 读路径STATE.md 当前报告的 total_phases gsd-tools state json # 3. 写路径重写 STATE.md 后再次检查 gsd-tools state sync gsd-tools state jsonstate json返回的progress.total_phases应始终等于roadmap analyze返回的phase_count。若两者不一致说明存在与 #549 同类的计数漂移应从 ROADMAP 标题格式或计数实现入手排查。把回归测试作为护城河本仓库的实践表明这类看起来正常实则错误的计数 Bug最有效的防御就是像 tests/roadmap.test.cjs L3558-L3608 那样用真实夹具同时覆盖读路径与写路径并把两个来源必须严格相等写成断言。在你的项目中复刻这一模式可以在阶段标题格式变化、约定演进时第一时间暴露分母污染。小结bug #549 的修复表面上是一行正则差异本质上却是一次架构原则的落地total_phases这类派生数据必须拥有单一事实源任何消费方都不应自带一套可能产生分歧的解析逻辑。GSD-Core 通过共享countRoadmapPhaseHeadings、以token 必须含数字作为判据让读路径state json、写路径state sync与权威分析roadmap analyze回归同频并用双层回归测试将契约永久钉死。这也是理解 GSD-Core 状态管理、规划文档解析与进度派生体系时最值得研读的一处微观样本。赞分享【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载相关推荐GSD 里程碑阶段过滤器修复解析让 CK-01 前缀阶段目录正确计入数字 ROADMAP 里程碑GSD 里程碑阶段过滤器修复解析让 CK 01 前缀阶段目录正确计入数字 ROADMAP 里程碑 本篇基于 get shit doneGSD仓库中的 ch人工智能AI 应用提示工程开发工具工作流自动化AI Agentgsd-core Route 0 恢复不完整阶段resume-incomplete-phase不变量的设计与实现gsd core Route 0 恢复不完整阶段resume incomplete phase不变量的设计与实现 导读 本文深入剖析 gsd core 中由get-shit-done validate.health 修复详解W006 不再对未开始的 Roadmap 阶段误报PR 3565get shit done validate.health 修复详解W006 不再对未开始的 Roadmap 阶段误报PR 3565 本文围绕 get s人工智能AI 应用提示工程开发工具工作流自动化AI Agent上一篇鸣潮自动化真的能帮你节省时间吗揭秘ok-ww智能辅助的实战应用下一篇Rufus 制作 Windows 11 LTSC 启动盘实战指南跳过在线账户直接用本地账户装机创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考