
【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载本文以.changeset/archived/3544-workstream-inventory-builder.md所记录的变更为主线深入 gsd-core 中Workstream Inventory工作流清单模块的架构设计它是如何以sdk/src/workstream-inventory/builder.ts规范 TypeScript 源为唯一真相来源生成bin/lib/workstream-inventory-builder.generated.cjs供安装器与命令使用并通过check-workstream-inventory-builder-fresh的新鲜度守卫freshness guard将 SDK 与 installer-facing 产物锁定为同步。文章同时展开 builder 本身的纯投影算法、类型契约、状态派生规则及其回归测试矩阵帮助读者理解workstream list / status / progress等命令背后的数据管线。变更背景为什么要引入一个生成的 Builder Seam该 changesettype: Added关联 PR 3548描述了一次架构收敛动作引入一个生成的 Workstream Inventory Builder seam并配以新鲜度守卫。其要点包括将sdk/src/workstream-inventory/builder.ts含测试确立为规范 builder 源码canonical builder source生成get-shit-done/bin/lib/workstream-inventory-builder.generated.cjs供安装器侧使用把check-workstream-inventory-builder-fresh接入 hooks/CI更新 inventory 文档与清单使SDK 产物与 installer-facing 产物保持同步。这与仓库中 ADR-457 的 build-at-publish 思路 一脉相承在 workstream-inventory-builder.cts 的模块头注释中明确写道手写的bin/lib/workstream-inventory-builder.cjs收敛为 TypeScript 单一真相来源行为逐字节保留仅增加类型。也就是说过去同一份逻辑需要在 SDK 侧与 CLI 安装侧各维护一份容易发生漂移生成式 seam 的目标就是让同一份规范代码只写一次、多处生成杜绝手写副本之间的行为分叉。需要说明的是当前仓库只读镜像中以src/workstream-inventory-builder.cts承载这份规范源码sdk/src/workstream-inventory/builder.ts与sdk/scripts/check-workstream-inventory-builder-fresh.mjs是 changeset / PRD 描述的产物路径阅读本文时可将两者视为同一概念在镜像中的不同落点。分层架构Builder 管纯投影Reader 管I/O 编排理解这个 seam 的第一步是认清模块边界。gsd-core将生成清单这件事拆成两个职责截然不同的模块模块职责I/Osrc/workstream-inventory-builder.cts纯投影把预先收集好的文件系统数据投影为类型化的WorkstreamInventory无 I/O、无异步src/workstream-inventory.ctsReader 适配器发现目录、读取 STATE.md / ROADMAP.md / 阶段文件、统计计划与摘要只做 I/O 编排投影全部委托给 BuilderReader 模块头注释明确了这一点workstream-inventory.cts拥有对.planning/workstreams/*状态的发现与只读投影命令处理器应从这个清单渲染输出而不是直接重扫工作流目录。纯投影逻辑在workstream-inventory-builder.cts本模块只做 I/O 编排。这样的分层带来几个可验证的好处可测试性Builder 是纯函数测试可以直接构造输入对象、断言输出对象无需文件系统tests/workstream-inventory.test.cjs 中大量buildWorkstreamInventory({...})单测即属此类可生成性纯投影无副作用天然适合作为规范源 → 生成产物的对象职责单一I/O 相关的故障处理文件缺失、权限、原子写、ledger 持久化全部收敛在 Reader 侧Builder 不会因磁盘状态而改变行为。输入输出契约从 PhaseFilesCount 到 WorkstreamInventoryBuilder 的核心入口是buildWorkstreamInventory(inputs: BuildWorkstreamInventoryInputs): WorkstreamInventory。其输入完全由调用方Reader预先收集主要包括name/projectDir/workstreamDir工作流身份与路径phaseDirNames阶段目录名列表phaseFilesCounts: PhaseFilesCount[]每个阶段目录的计划数、摘要数、规范 phase key、目录 mtime、是否属于当前里程碑、验证结论roadmapPhaseCount/currentMilestonePhaseCount分母来源整份 ROADMAP 的阶段数或当前里程碑声明的阶段数stateProjection从 STATE.md 投影出的Status/Current Phase/Last ActivityfilesExistROADMAP / STATE / REQUIREMENTS 三个文件是否存在milestoneShipped与milestoneShippedSignal权威发货信号及其来源强度。PhaseFilesCount上几个字段值得展开源码注释有明确语义phaseKey目录的规范阶段键由 src/phase-id.cts 的phaseKeyFromDir得出。两个同号但不同写法的陈旧目录Bug #2445 场景05-x与5-x-old共享同一个 key在 rollup 中必须只计一次否则分子会超过按不同阶段计数的分母mtimeMs目录修改时间用于同 key 目录冲突时的决胜取更新的inMilestone该阶段目录是否属于当前里程碑仅当里程碑作用域生效时有意义complete阶段完成结论由具备 I/O 能力的调用方通过isPhaseCompletesrc/verification.cts 中的单一 owner计算后传入。Builder 作为纯投影不能自行调用 owner缺失/未定义一律按未完成?? false处理绝不默认为完成。输出WorkstreamInventory的关键字段字段语义status/status_source/status_conflict工作流状态field原样取自 STATE.md或derived派生两者不一致即为冲突milestone_shipped_unverified发货信号被当前里程碑自身工件否定、未被采信phases: PhaseStatus[]每个阶段目录的statuscomplete/in_progress/pending、plan_count、summary_countphase_count/completed_phases/roadmap_phase_count阶段总数、已完成阶段数、分母阶段数total_plans/completed_plans/progress_percent计划总数、已完成计划数、完成百分比经clampPercent钳制核心算法一pickRollupWinners 与每 key 只取一个胜者Builder 中最关键的去重逻辑是导出的pickRollupWinnersT(sortedItems, keyOf, mtimeOf, includeItem?)。它从预排序列表中为每个 key 挑选唯一获胜项mtimeMs更新者胜完全平局时按排序顺序的**在任者incumbent**胜——因为只有严格更大的 mtime 才会替换它。includeItem允许调用方在比较前排除某些条目例如非当前里程碑的目录过滤发生在 mtime 比较之前因此被排除的条目永远不可能在平局或比较中胜出。源码注释给出了这个函数被抽成唯一共享实现的来龙去脉#2645 评审发现此前存在两份手写副本并已静默分叉——workstream-inventory.cts的 ledger 胜者选择直接比较裸 mtime、不带作用域过滤而本模块内部的rollupDirByKey先过滤掉非里程碑目录。一次 checkout/rebase 重置 mtime 后一个mtime 更新但属于旧里程碑的陈旧目录就可能赢得 ledger 侧的选择、却输掉 builder 侧的选择从而对真正计入completed_phases的阶段重新打开 #2645 的漏洞。注释中的结论很有代表性两条手写副本使用相同规则的注释并不能保证它们真的相同一个共享函数才能。在buildWorkstreamInventory内部rollupDirByKey正是用这个共享函数构建的const rollupDirByKey pickRollupWinners( [...phaseDirNames].sort(), (dir) countsMap.get(dir)?.phaseKey ?? dir, (dir) countsMap.get(dir)?.mtimeMs ?? 0, (dir) !(scoped countsMap.get(dir)?.inMilestone false), );这保证了陈旧同号目录不会让completed_phases超过分母被作用域排除的目录绝不参与统计。对应的回归测试在 tests/workstream-inventory.test.cjs 的pickRollupWinners: an excluded (out-of-milestone) item can never win over an included one, even with a newer mtime用例中分别构造了正向、逆序输入与 unscoped 对照组。核心算法二里程碑作用域与分子永不超分母不变式#2562 修复的缺陷类别是把项目全部阶段历史当作当前里程碑来统计或把已声明但从未搭建目录的阶段从分母中悄悄丢掉最终把完成百分比错误地推高到 100%。Builder 的处理方式当里程碑作用域开启milestoneScoped或currentMilestonePhaseCount 0时只有inMilestone true的阶段目录进入完成 rollup分母取currentMilestonePhaseCountROADMAP## Progress表为当前里程碑声明的阶段数包含已声明但未搭建目录的阶段作用域关闭时回退到旧行为分母为整份 ROADMAP 的阶段数不变式硬校验在作用域下若completedPhases effectivePhaseCount直接抛出invariant violated错误而不是用旧的Math.min(100, …)静默钳制到 100%。注释明确说明分子超过分母意味着两侧在不同的 phase-key 空间中推导旧钳制把这种不一致掩盖成了 100%新实现让它大声失败。测试矩阵为这个不变式提供了丰富的用例a stale same-numbered directory does not double-count the numerator、builder: a numerator above the denominator throws instead of capping to 100%、a located-but-empty current milestone reports 0%, not its predecessors 100%等。其中已声明但为空的里程碑判定尤为精巧当currentVersion非空、当前里程碑没有任何已归属阶段、且 ROADMAP 存在versionSectionFound/missingExplicitVersion/ 全部行都被归属到其他里程碑这三类见证之一时判定为已声明但空从而避免回退到整个项目历史即当前里程碑的错误统计。状态派生shipped signal 是主张不是事实Builder 对status的派生遵循 #1913 的原则不信任可变的 STATE.mdStatus字段而优先采信权威发货信号。信号分为三种强度MilestoneShippedSignalsnapshotmilestones/version-ROADMAP.md存在——由milestone complete写入是最强的工具产物信号heading活动 ROADMAP 中当前里程碑标题带发货标记——操作员手工输入的散文最弱legacy仅在无法确定当前里程碑版本时启用的项目生命周期级回退#1913 对畸形/遗留项目的保护null无任何发货信号。#2562 评审进一步要求返回哪个信号触发了而非布尔值因为两种信号的交叉校验强度不同用一个检查同时服务两种形状会回归最常见的归档场景headingROADMAP 未被归档里程碑声明的每个阶段都应已在磁盘且完成因此以完整完成率为门槛还能兜住已声明但未搭建的无目录阶段snapshotmilestone complete会把阶段目录移入milestones/version-phases/同时复制绝不截断活动 ROADMAP因此干净归档按构造就应读 0/N。若直接以完成率作门槛会把每个已归档里程碑的milestone complete全部剥掉。正确的门槛是合取存在存活的当前里程碑阶段目录即归档不干净——阶段被新增或重开且完成率不足。注释特别强调只要求存活目录自身未完成太窄——一个已完成的存活目录旁若有一个已声明但未搭建的阶段同样会复现症状而无目录的阶段无处可查。当信号与工件矛盾shippedContradicted时状态降级为in_progress即使 STATE.md 字段自己也写着milestone completeartifactOverride分支——被拒绝的主张不能从另一扇门重新进来。这些语义由milestone_shipped_unverified显式暴露而非静默吞掉。完成结论的单一 OwnerADR-3180 §7.4 与 disk-strict自 ADR-3180 §7.4#3186起阶段是否完成不再由 builder 从 plan/summary 计数 验证状态本地重算而是统一路由到 src/verification.cts 的isPhaseComplete单一 owner。Builder 只消费调用方传来的PhaseFilesCount.complete。这消除了在本地后处理规范 owner 的结果这一被 §7.4 禁止的旁路——旧实现正是因此复现了 disk-strict 头条场景#3168零计划 通过的验证被读成pending而非complete。disk-strict 的后果很直接isPhaseComplete无条件要求verification.status passed。一个没有*-VERIFICATION.md的阶段missing例如禁用 verifier 的项目永远不算完成——旧禁用 verifier 的项目凭摘要数达标即可完成的容忍被有意移除且 changeset 中明确披露了这一行为变更。对应测试a missing verdict is NOT complete (verifier-off tolerance retired, disk-strict)与parity: every verifier status other than passed blocks completeness将这一约定钉死。证据防篡改#2645 验证台账ledger与原子写虽然 ledger 的读写属于 Reader 侧职责但它与 Builder 的 rollup 语义强耦合是理解整个清单可信度的关键一环。问题#2645是验证结论每次调用都从*-VERIFICATION.md现读于是验证器跑过、发现缺口、报告后来被删除与验证器从未跑过都坍缩成同一个missing哨兵——只删一个文件就足以静默抬高完成百分比Goodhart 漏洞。修复方案在工作流目录级维护.verification-ledger.json绝不放在会被删除的阶段目录内部记录每个 phase key 最近一次真实非missing结论实时读取为missing时回退到台账。台账读取是三态而非两态absent——文件根本不存在未采纳台账行为与 #2645 之前完全一致避免上线当天全项目被一次性降到in_progresscorrupt——文件存在但无法读取/解析含断链符号链接通过lstatSync与真缺失区分失败关闭ok——文件可解析有记录用记录无记录的阶段按unrecorded失败关闭防止同一漏洞针对单个阶段重开。写入侧采用原子写同目录临时文件 rename并对 Windows 的瞬时占用做指数退避重试EPERM/EBUSY/EACCES最多 5 次25ms 起步翻倍任何失败都只丢本次观测、绝不留下半截 JSON 或孤儿临时文件。值得注意的是disk-strict 上线后 ledger 的删除后回放旧结论记忆已被 #3186 退役——isPhaseComplete每次都无条件现读磁盘报告被删即读missing→ 不完成与roadmap analyze/init manager/phase complete对同一磁盘状态的判定完全一致。测试Row 9的属性测试任意真实结论序列后删除报告阶段永不完成与Row 11/12/16/17的故障注入写失败、读失败、目录不可建、rename 失败覆盖了这些路径。生成式 Seam 与新鲜度守卫SDK 与安装产物的同步保障回到 changeset 的主题——生成 seam 的同步机制规范源sdk/src/workstream-inventory/builder.ts含测试持有 builder 的唯一实现生成脚本sdk/scripts/gen-workstream-inventory-builder.ts负责从规范源发出gsd-core/bin/lib/workstream-inventory-builder.generated.cjsCLI/安装器侧与sdk/src/query/workstream-inventory-builder.generated.tsSDK 侧两份产物新鲜度守卫sdk/scripts/check-workstream-inventory-builder-fresh.mjs校验生成产物是否与规范源一致并被接入 hooks/CI——任何只改了规范源而未重新生成产物的提交都会被拦住文档与清单同步inventory 文档与 manifest如 CONTEXT.md、docs/INVENTORY.md、docs/INVENTORY-MANIFEST.json同步更新使 SDK 与 installer-facing 工件始终处于同一版本。这套机制的意义在于bin/lib/workstream-inventory-builder.generated.cjs是命令侧实际加载的模块测试文件中的require(../gsd-core/bin/lib/workstream-inventory-builder.cjs)可作证而 SDK 侧又需要类型化版本如果没有生成式 seam 和新鲜度守卫两份产物迟早分叉而pickRollupWinners的故事已经证明手写两份相同逻辑在实践中的不可靠性。消费者与扩展workstream list / status / progress 的数据管线Builder 产出的WorkstreamInventory[]是多个命令的公共数据源。Reader 模块导出的listWorkstreamInventories(cwd)返回WorkstreamInventoryListflat或workstream模式、活动工作流、有序列表并按活动工作流置顶、其余按名称排序输出getOtherActiveWorkstreamInventories则过滤出其他未完成的工作流供需要切换/感知其他工作流的命令使用。inspectWorkstream(cwd, name, options)是单工作流入口还支持注入writeDiagnostic侧通道当验证陈旧性检查#3057 B3因 fs/时钟故障无法完成时以结构化{ phaseDir, reason }输出 stderr 诊断不影响 rollup 结果——路由保持逐字节不变。在 src/smart-entry.cts 中也能看到对同一套完成语义的引用镜像workstream-inventory-builder.cts的里程碑完成信号判断说明这份纯投影逻辑是全项目共享的单一事实来源而非某个命令的局部工具。回归保障一张测试矩阵钉住四类缺陷tests/workstream-inventory.test.cjs 是这份模块最完整的验收记录测试按缺陷编号组织#1913milestoneShipped覆盖过期的executing字段derivedconflict归档快照 / ROADMAP SHIPPED 标记都能把状态派生为milestone complete#2562当前里程碑作用域的全部边界——已声明但未搭建的阶段计入分母、旧里程碑阶段不进分子、零填充/项目码前缀/强调/标签装饰下表格单元格与其目录永远得出同一 phase keyfast-check 属性测试1000 轮、版本边界v2.0不匹配v2.0.1、发货主张被自身工件否定时状态不得断言完成含 STATE 字段复读被拒的ws-field-echo用例#2645删除*-VERIFICATION.md不得抬高完成度、台账三态与失败关闭、原子写故障注入、pickRollupWinners的共享实现保证、陈旧目录绝不污染获胜目录#3057 B3验证陈旧性检查不确定时的诊断输出与 rollup 不变。此外inspectWorkstream cannot trip the Builder invariant用例把多种对抗形状前序里程碑、重复 key、无目录阶段、未归属行、项目码前缀、子阶段一次性塞进一个工作流断言分子不超过分母且百分比低于 100——因为listWorkstreamInventories遍历时不捕获异常Builder 的不变式抛出会拖垮workstream list / status / progress的全部工作流。小结从sdk/src/workstream-inventory/builder.ts规范源到生成的bin/lib/workstream-inventory-builder.generated.cjs再到 hooks/CI 中的check-workstream-inventory-builder-freshgsd-core 用一条**规范源 → 生成产物 → 新鲜度守卫 → 文档清单**的链路把 Workstream Inventory 的纯投影逻辑锁成单点事实来源。其内部的pickRollupWinners去重、里程碑作用域不变式、shipped signal 交叉校验、单一 completion owner 与验证台账共同保证了workstream list / status / progress输出的状态与百分比不会被陈旧目录、过期字段或证据删除所篡改。想深入底层建议依次阅读 src/workstream-inventory-builder.cts纯投影、src/workstream-inventory.ctsI/O 编排与 ledger、tests/workstream-inventory.test.cjs回归矩阵并对照 ADR-3524 理解生成式 seam 在整个 SDK/安装器体系中的位置。赞分享【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载相关推荐gsd-core 修复实战init.milestone-op 与 roadmap.analyze 的 Workstream 作用域解析修复PR 3196gsd core 修复实战 init.milestone op 与 roadmap.analyze 的 Workstream 作用域解析修复PR 3196agent-skills中的微服务架构构建灵活且可扩展的应用系统agent skills中的微服务架构构建灵活且可扩展的应用系统 agent skills是一个为AI编码代理提供生产级工程技能的项目其内部实现了基于微服务AI 技能开发工具AI 评测Benchmarkgsd-core 命令参数投影单次索引优化parseNamedArgs 从 O(flags×argv) 到 O(argvflags) 的演进实录gsd core 命令参数投影单次索引优化parseNamedArgs 从 O flags×argv 到 O argvflags 的演进实录 导读 本文以创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考