尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

gsd-core milestone.complete 输出质量修复:MILESTONES.md 头部去重、checkbox 阶段泄漏与 one-liner 提取边界

gsd-core milestone.complete 输出质量修复:MILESTONES.md 头部去重、checkbox 阶段泄漏与 one-liner 提取边界 【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载milestone.complete别名milestone complete是 gsd-core 里程碑收尾的核心命令它把 ROADMAP/REQUIREMENTS 归档进.planning/milestones/、把阶段目录移入归档区、在 MILESTONES.md 追加发布记录并重写 STATE.md。本篇文章围绕 PR #146 对该命令的三处输出质量修复展开——头部版本号重复v1.0 v1.0、checkbox 子弹点声明的阶段泄漏进 all phases 回退、one-liner 文本越过首个标题边界被误提取——结合 milestone.cts、roadmap-parser.cts、core-utils.cts 的源码与 milestone.test.cjs 的回归测试说明每个缺陷的成因、修复机制与可验证的回归保障。读完你将能理解milestone complete写 MILESTONES.md、统计阶段集合、抽取成就摘要时的边界语义并能在自己的里程碑收尾输出异常时快速定位根因。一、背景milestone complete的输出面与这三处缺陷的定位在 gsd-core 中里程碑收尾由 complete-milestone.md 工作流驱动核心归档动作委托给 CLIgsd_run query milestone.complete v[X.Y] --name [Milestone Name] --confirm $ARCHIVE_QUICK_FLAG--confirm自 #3726 起成为强制项该命令是不可逆的单向门ROADMAP/REQUIREMENTS 归档、阶段目录被 MOVE、STATE.md 重写未确认时拒绝一切变更--dry-run则预览精确的移动清单而不落盘。工作流文档明确列出 CLI 负责的输出面创建.planning/milestones/目录将 ROADMAP.md 归档为milestones/v[X.Y]-ROADMAP.md将 REQUIREMENTS.md 归档为milestones/v[X.Y]-REQUIREMENTS.md带归档头归档审计文件如存在创建/追加 MILESTONES.md 条目成就accomplishments从各阶段 SUMMARY.md 提取更新 STATE.md状态、最近活动可选--archive-quick把.planning/quick/目录移入milestones/v[X.Y]-quick/。PR #146changeset 类型Fixed修复的三处缺陷都落在这个命令的“写出”环节MILESTONES.md 的头部排版、阶段归属集合的统计、以及 SUMMARY.md 成就文本的提取。三者分别对应一个独立的数据来源既有 MILESTONES.md 内容、ROADMAP.md 窗口、SUMMARY.md 正文因此修复彼此独立、测试也各自成组。二、修复一MILESTONES.md 头部不再产生v1.0 v1.0重复版本号2.1 缺陷现象收尾时若.planning/MILESTONES.md已存在命令需要把新条目插入到头部标题之下、并保持“新条目在前”的倒序reverse chronological。修复前头部排版逻辑在特定输入下会把版本号写出两次例如## v1.0 v1.0 (Shipped: ...)。2.2 源码实现单次 ^ 锚定的头部匹配当前实现在 milestone.cts 中按四种形态分派写入if (!existing.trim()) { // 空文件——当作新文件 platformWriteSync(milestonesPath, # Milestones\n\n${milestoneEntry}); } else { // 在头部行之后插入保持倒序新条目在前 const headerMatch existing.match(/^(#{1,3}\s[^\r\n]*\r?\n(?:\r?\n)?)/); if (headerMatch) { const header headerMatch[1]; const rest existing.slice(header.length); platformWriteSync(milestonesPath, header milestoneEntry rest); } else { // 无可用头部——直接前插条目 platformWriteSync(milestonesPath, milestoneEntry existing); } }这里的关键细节源码注释 #3415 明确记录头部正则采用非全局、^锚定、不带/m的形态因此只在位置 0 做一次匹配尝试绝不会在每一偏移处重扫配合无嵌套重复组避免了 #2128 类灾难性回溯注释给出的实测5MB 对抗输入下仍为线性耗时10KB 约 0.11ms5MB 约 6.9msheaderMatch捕获的是“首个 H1/H2/H3 标题行 其后的空行”插入点严格落在标题与既有正文之间。若头部无法识别则退化为直接前插——但此时不会再把版本号拼接进既有头部重复版本号也就无从产生。2.3 回归测试倒序语义被锁定tests/milestone.test.cjs 用两条测试钉死了头部行为prepends to existing MILESTONES.md (reverse chronological)预置# Milestones\n\n## v0.9 Alpha (Shipped: 2025-01-01)\n---执行milestone complete v1.0 --name Beta --confirm后断言v1.0 Beta出现在v0.9 Alpha之前——既验证新条目插入头部之后也隐式验证头部未被重复改写three sequential completions maintain reverse-chronological order连续完成 v1.0、v1.1、v1.2 三次断言三者位置满足v1.2 v1.1 v1.0锁定多轮收尾下插入语义的稳定性。配合 #3685 引入的milestones_updated真实内容 diff不再是硬编码true命令现在能如实报告 MILESTONES.md 是否真正发生了变化见 milestone.cts。三、修复二checkbox 子弹点声明的阶段不再泄漏进 all phases 回退3.1 缺陷现象ROADMAP.md 有两种常见的阶段书写风格ATX 标题风格### Phase N: name和 bullet/checkbox 风格- [ ] **Phase N — name**由 roadmapper 的 bullet-house 风格产出。修复前当里程碑窗口内用 checkbox 子弹点声明阶段时这些阶段会泄漏进 all phases 回退pass-all filter——而milestone complete是破坏性消费者pass-all 回退会让归档范围从“本里程碑的阶段”无声扩大为“磁盘上所有阶段目录”直接威胁归档正确性。3.2 缺陷根因阶段集合扫描不识别 bullet 语法阶段归属集合由 roadmap-parser.cts 的scanMilestonePhaseIdSets构建其源码注释 #2199 明确记载了修复语义// #2199: also count bullet/checkbox phase entries (- [ ] **Phase N — name**) // so a bullet-house-style ROADMAP populates the milestone phase set instead of // collapsing to a zero-count pass-all filter.对应的 bullet 行模式定义于同文件 roadmap-parser.ctsconst BULLET_PHASE_LINE_PATTERN /^\s*[-*]\s(?:\[[ xX]\]\s)?\*\*Phase\s([\w][\w.-]*)(?:\s*\([^)\n]{0,200}\))?\s*[—–:\-]\s*(.?)\*\*/im;它接受[ ]/[x]/[X]三种勾选态分隔符兼容 em-dash—、en-dash–、连字符与冒号。扫描时先按 ATX 标题level 2–4fence 感知收集ids再对去 fence 后的正文用BULLET_PHASE_LINE_PATTERN补扫gim全局模式最后合并表格声明行#3577——三者共享同一个集合。3.3 为什么泄漏危害更大pass-all 是破坏性路径上的静默放大阶段过滤器的 pass-all 回退语义在 roadmap-parser.cts 中有完整注释当milestonePhaseNums.size 0时返回恒真过滤器同时保留scopeUNREADABLE/UNSCOPED/TRUNCATED供破坏性消费者自行拒绝——即 ADR-3180 Decision 3 的“双层级策略”读路径可以安全降级写路径必须拒绝。msilestone.cts 正是这个消费者当窗口 scope 为UNREADABLE时milestone complete拒绝归档阶段目录并给出机器可读的phases_archive_skipped/phases_archive_skip_reason而 checkbox 阶段在修复前因扫描不到而塌缩成 pass-all等于把“窗口解析不出来”伪装成“没有阶段需要归档”导致误归档。修复后bullet/checkbox 声明被计入集合窗口不再是空集milestone complete就能按真实窗口精确归档——这一同路径还由listMilestonePhaseDirsphase-locator.cts在统计循环、--dry-run预览与真实归档三处共享同一派生结果#3597 / ADR-3180 Decision 2三者永不互相矛盾。四、修复三one-liner 提取不再越过首个标题边界4.1 缺陷现象MILESTONES.md 的成就清单accomplishments来自各阶段 SUMMARY.md。修复前提取逻辑匹配正文中第一个**...**加粗段——这会在两类输入上出错标签吞噬历史缺陷 #2660**One-liner:** prose形态下第一个加粗段只含One-liner:标签本身产出- One-liner:这种空转条目越界提取本次修复若 SUMMARY 开头是# Rules、# Deviation Notes这类非摘要标题及其加粗行规则列表、偏差说明提取器会把第一个标题边界之后、无关段落里的加粗文本当成里程碑成就写入 MILESTONES.md。4.2 修复实现锚定 summary-shaped 标题当前实现在 core-utils.cts源码注释 #3170 记载了修复原则// #3170: anchor to a summary-shaped heading (Summary / Overview / // Accomplishments) so an incidental first heading (a rule list, task // breakdown, deviation note) does not contribute its first bold run as the // deliverable one-liner. Iterate headings in document order and extract from // the first summary-shaped one that has a bold run; fall back to null (not the // wrong text) when no such heading exists. const headingRe /^#\s*([^\n]*)\n\*\*([^*\n])\*\*([^\n]*)/gm; while ((match headingRe.exec(body)) ! null) { if (!/summary|overview|accomplish/i.test(match[1])) continue; // 加粗标签如 One-liner:后跟冒号时取冒号后的散文否则取加粗内文 ... } return null;三个要点按文档顺序遍历所有标题只认Summary/Overview/Accomplishments形态大小写不敏感的标题其下的首个加粗段才是候选加粗段形态二义性处理若加粗内文以冒号结尾**One-liner:**取冒号后的散文Real prose here.否则直接取加粗内文**Shipped the thing.**→Shipped the thing.无匹配时回退为null而非错误文本——调用方 milestone.cts 先读 frontmatter 的one-liner字段缺失时才用extractOneLinerFromBody兜底再退化为空成就- (none recorded)绝不把无关加粗段落写进里程碑记录。4.3 回归测试矩阵tests/milestone.test.cjs自bug-2660-one-liner-extraction.test.cjs合并而来以行为表逐行锁定用例输入形态期望输出row 1# Rules意外首标题## Summary取 Summary 标题下的加粗内文忽略# Rules的加粗行row 2仅有# Deviation Notes等非摘要标题null而非无关加粗文本row 3# Overview标题识别 Overview 为摘要形态并提取row 4# Phase 1: Foundation Summary**One-liner:** proseprose#2660 标签形态保持a/b/c/d/e标签/纯 frontmatter/无加粗/加粗嵌套/空散文标签取冒号后散文、纯 frontmatter 返null、无加粗返null、嵌套加粗保留、空散文返null此外 milestone.test.cjs 还保留了“正文无 frontmatter 时从正文提取”的集成用例确认兜底路径在真实归档流程中可达。五、三项修复的共同工程语义将三处修复放到一起看它们共享同一条质量原则——“生成物绝不能静默出错”头部重复版本号是排版层的静默失真靠精确的头部匹配 真实内容 diffmilestones_updated消除checkbox 阶段泄漏是集合语义层的静默放大靠 bullet 语法纳入扫描、并由scope字段把“拒绝”权限下放给破坏性消费者解决one-liner 越界提取是文本语义层的静默张冠李戴靠 summary-shaped 标题锚定 null回退解决。三者都在 milestone.test.cjs头部倒序、归档路径、one-liner 矩阵与 roadmap-parser.ctsscanMilestonePhaseIdSets的标题/子弹/表格三源合并中留有可重复的回归证据后续改动一旦破坏任一语义测试组即可在 CI 中拦截。这也解释了为何该 changeset 被归类为Fixed而非Enhancement它不引入新能力只是让既有收尾输出在三种边界输入下恢复正确。六、如何验证与自查在自己的 gsd-core 项目中可以按以下方式复现验证三项语义头部去重预先写入带头部与旧条目的.planning/MILESTONES.md执行gsd_run query milestone.complete v1.0 --name Test --confirm --dry-run先用--dry-run预览再检查实际写入文件头部是否只出现一次版本号checkbox 阶段归属对采用- [ ] **Phase N — name**风格的 ROADMAP 窗口执行 dry-run观察would_archive.phases是否只包含该窗口内的阶段目录而非全部磁盘目录若窗口无法解析确认结果中phases_archive_skipped: true及对应phases_archive_skip_reason被如实上报one-liner 提取构造一个以非摘要标题如# Rules开头的 SUMMARY.md确认 MILESTONES.md 条目不会出现该标题下的加粗文本而# Summary标题下的加粗段会被正确收录。三项行为的实现锚点分别在 milestone.ctsMILESTONES.md 头部写入与milestones_updateddiff、roadmap-parser.cts三源阶段集合扫描与 core-utils.ctsone-liner 标题锚定配套回归测试位于 tests/milestone.test.cjs可作为继续深入阅读的入口。赞分享【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载相关推荐Vitest disableConsoleIntercept 配置详解控制 console 拦截与调试日志输出Vitest disableConsoleIntercept 配置详解控制 console 拦截与调试日志输出 Vitest 默认会在测试运行期间拦截 congsd-core 阶段移除重编号修复phase remove --force 如何避免 ROADMAP 折叠gsd core 阶段移除重编号修复 phase remove force 如何避免 ROADMAP 折叠 导读 本篇文章讲解 gsd core 中 phasGSD 斜杠命令命名空间治理从 stale /gsd:cmd 泄漏修复看 gsd-core 的双向规范化体系GSD 斜杠命令命名空间治理从 stale /gsd:cmd 泄漏修复看 gsd core 的双向规范化体系 本文围绕 gsd core 的一条 chang上一篇Claude Desktop中文汉化补丁让AI助手说中文的完整解决方案下一篇gh_mirrors/de/deprecated-version部署教程从本地开发到生产环境创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表