拓冰建站拓冰建站
首页 / 资讯中心 / 正文

GSD 仓库中的 PRD 实践:从需求文档规范到 CJS↔SDK 硬接缝迁移实战

GSD 仓库中的 PRD 实践从需求文档规范到 CJS↔SDK 硬接缝迁移实战【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done本篇技术指南聚焦 GitHub Trending 仓库 getshi / get-shit-doneGSD中的docs/prd/目录规范与其唯一收录的参考 PRD——#3524 CJS↔SDK 硬接缝迁移。PRD产品需求文档在 GSD 中负责在动手编码前写清功能的what做什么与 why为什么与记录how怎么做的 ADR 形成互补文章将带你掌握 GSD 的 PRD 命名/提交流程、PRD↔ADR 双文档配合模式并以上述六阶段迁移计划为完整案例结合仓库当前的生成器与 CI 门禁实现理解「单一事实源 生成产物 freshness 校验」这一消除 CJS/SDK 漂移的系统化工程方案。PRD 在 GSD 中承担的角色先写 why再谈 how根据 docs/prd/README.md 的说明docs/prd/目录存放 GSD 的 Product Requirements DocumentsPRDs。一份 PRD 在功能实现开始之前先捕捉该功能的what做什么与why为什么——它论证一个功能为什么值得做、定义其验收标准而docs/adr/下的 ADRArchitecture Decision Record记录的则是交付该功能所选定的架构机制how。两者的关系是互补而非重复文档类型目录回答的问题典型内容PRDdocs/prd/what 与 why问题陈述、目标与非目标、分阶段实施计划、每阶段验收标准、回滚方案ADRdocs/adr/how一项架构决策是什么、为什么选它、后续影响append-only不可改写GSD 的约定是「先开 issue → 获批 → 写 PRD或 ADR→ 再写代码」。对于一次涉及架构的较大改动通常由 ADR 定义目标架构、由 PRD 定义「在不破坏运行中系统的前提下如何抵达」的实施路径。仓库根目录的 CONTRIBUTING.md 也把docs/adr/列为维护者拥有的、必须视为权威的贡献标准之一。目录约定为什么新 PRD 必须用 issue# 做文件名前缀docs/prd/的命名规范与 ADR 完全一致都使用issue# 前缀 kebab-case 短横线 slugdocs/prd/issue#-kebab-slug.md例如docs/prd/3491-bar-feature.md表示该文件对应 GitHub issue #3491 中的功能特性。README 明确强调The GitHub-assigned issue number is the prefix. Do not compute a sequential number locally.即不要本地自增编号。完整提交流程见 CONTRIBUTING.md — Proposing an ADR or PRD。该规范在 docs/adr/README.md 中有更详细的动机说明两位开发者各自在main上计算「下一个 ADR 序号」会撞出同一个整数——仓库历史里0010-*已重复两次、0011-*重复了三次就是旧「本地计算序号」约定的残留。而 GitHub issue 号是服务端原子分配的issue 一旦打开该编号就在全局被占用两个 PR 各自用不同的 issue# 做前缀就永远不会冲突。另外docs/prd/README.md还有一条历史说明docs/adr/0011-review-default-reviewers-prd.md早于本目录存在被保留为不可变历史记录不是值得模仿的模式新的 PRD 一律放在docs/prd/。提议一个 PRD/ADR 的完整流程按 CONTRIBUTING.md — Proposing an ADR or PRD 的端到端流程核心步骤如下开 issue 并等待批准为 ADR 开 enhancement 类 issue如重访既有区域、为 PRD/新架构面开 feature 类 issueissue 必须填写完整。维护者须在创建任何文件前打上approved-enhancement/approved-feature标签或确认 chore。以 GitHub 分配的 issue 号为文件名前缀在以 issue 命名的分支上创建文件docs/adr/issue#-slug.mdADRdocs/prd/issue#-slug.mdPRD分支名docs/issue#-slug用合适模板开 PR并在 PR body 中以Closes #issue#关闭对应 issue。硬性约束包括一个 issue 一份 ADR 或 PRD 一个 PR不允许把多个决策塞进同一文件或同一 PR使用旧式NNNN-*顺序编号的新文件会在合并前被要求改名文件放错目录docs/adr/与docs/prd/混淆也会被拒。参考实例是issue #3485 获批后其编号成为前缀docs/adr/3485-adr-prd-naming-convention.md分支为docs/3485-adr-prd-naming-convention。目录索引与唯一参考 PRD#3524 CJS↔SDK 硬接缝迁移截至当前仓库状态docs/prd/下除 README 外只有一个索引项可作为学习 PRD 写作结构的完整范本PRDTitleStatus3524-cjs-sdk-hard-seam.mdCJS↔SDK hard seam — phased migration (#3524)Reference其关联 ADR 为 docs/adr/3524-cjs-sdk-hard-seam.md。ADR 定义目标架构每个 Shared Module 只有一个事实源复用既有的command-aliases.generated.*先例而这份 PRD 定义如何在不破坏运行中系统的前提下抵达目标迁移按顺序编排让最小、最低风险的 Shared Module 先交付作为该模式的可用证明后续各阶段把同一模式应用到更高风险模块每个阶段都可独立交付、独立回滚。问题陈述CJS↔SDK 边界的结构性渗透GSD 同时存在两套运行时——供 shell 脚本兼容的 CJS CLIgsd-tools代码位于get-shit-done/bin/lib/*.cjs与 SDKTypeScript代码位于sdk/src/query/*.ts。两者之间当前是结构上可渗透的多个 Shared ModuleSTATE.md Document Module、Workstream Inventory Module 等以「手工同步的成对 .cjs/.ts 文件」形式存在实现逐字符相同常量CONFIG_DEFAULTS、VALID_CONFIG_KEYS也在两侧各定义一份。边界目前仅靠两道防线「把守」一个命名一致性测试tests/config-schema-sdk-parity.test.cjs只读 handler 的输出奇偶 golden 测试sdk/src/golden/read-only-parity.integration.test.ts这些测试能抓住部分漂移但会漏掉以下类型PRD 原文逐条列出结构漂移默认值下#3523 中顶层branching_strategy被 CJS 返回为none、被 SDK 返回为phase警告/报错文案漂移#3523 中 CJS 误报警告、SDK 静默拼接变更路径漂移两侧各自测试缺少跨侧的变更 fixture新模块漂移某侧新增常量而另一侧未加完全不可见。#1535、#1542、#2047/#2052、#2638/#2655、#2653/#2670、#2687/#2706、#2798/#2816、#3055/#3116、#3523 等反复出现的 bug 都属于这一形态。修复是机械式的对每对手工同步文件把一侧替换为由另一侧事实源生成的产物复刻既有的sdk/scripts/gen-command-aliases.tssdk/scripts/check-command-aliases-fresh.mjs模式。目标与非目标目标Goals消灭漂移 bug 类别具体而言接缝落地后四个月内零新增带drift-recurrence追溯标签的 bug每个 Shared Module 只有一个事实源由 PR 时的逐模块 freshness 检查强制保证成对的手工同步.cjs/.ts文件变得无法合并lint 门禁不引入新的构建工具——既有生成器模式可扩展。非目标Non-goals不移除 CJS CLIgsd-tools为 shell 脚本后向兼容而继续存在其 dispatcher 在 Phase 5 之后委托给 SDK runtime bridge外部 CLI 契约不变不把 CJS-only 模块graphify、gsd2-import、schema-detect、fallow-runner、intel、drift迁移为 SDK handler在 verify 面拥有共享 Interface 之前不定义 Verify Module——verify 面加深属未来增强的前置工作。通用方法把 alias 生成模式推广到每个 Shared Module仓库中已经存在共享 CJS/SDK 模块的工作先例sdk/scripts/gen-command-aliases.ts从单一 TypeScript 源同时产出sdk/src/query/command-aliases.generated.ts与get-shit-done/bin/lib/command-aliases.generated.cjssdk/scripts/check-command-aliases-fresh.mjs作为 CI freshness 门禁任一生成文件偏离源即告失败。该 PRD 将此模式推广到每个被迁移的 Shared Module标准六步为把一侧提升为事实源选择 TS 源因为它已携带类型编写sdk/scripts/gen-module.ts同时产出.generated.ts与.generated.cjs仿照check-command-aliases-fresh.mjs编写sdk/scripts/check-module-fresh.mjs把手工编写的 CJS 文件替换为对生成文件的薄 re-export将 freshness 检查接入 CI跑绿一个发布周期后通过移除废弃的 re-export让手工作者内容从历史视图里消失。另设一个常驻 CI lintscripts/lint-shared-module-handsync.cjsPhase 6 引入阻断任何新的手工同步对合入。六阶段迁移计划详解PRD 主体每个阶段被控制在 12 个 PR 内可交付各有自己的 GitHub issue链接回 #3524且仅在上一个阶段交付后才开启。以下是各阶段的要点、验收标准与回滚方案。Phase 1 — STATE.md Document Module最小可行证明为何先做get-shit-done/bin/lib/state-document.cjs与sdk/src/query/state-document.ts已是一对逐字符相同的手工同步纯变换文件头明确声明「Pure transforms for STATE.md text. This module does not read the filesystem and does not own persistence or locking」删除测试一接触即通过一侧一旦成为生成产物另一侧立即可删除。这是最安全的第一步也是证明生成器模式对可执行逻辑而非仅 alias 表有效的规范例证。范围把sdk/src/query/state-document.ts提升为sdk/src/state-document/index.ts下的源或原地保留实现时定夺写sdk/scripts/gen-state-document.ts产出get-shit-done/bin/lib/state-document.generated.cjs写sdk/scripts/check-state-document-fresh.mjs把bin/lib/state-document.cjs内容替换为对生成文件的薄 re-export保留原文件名使调用方如workstream-inventory.cjs:16无需改 import将 freshness 检查接入 CI。验收标准bin/lib/state-document.cjs仅含 re-exportfreshness 检查在 CI 通过、故意失同步时失败CJSstate.cjs、workstream-inventory.cjs与 SDKstate-mutation.ts、state-project-load.ts及其他导入者所有调用点照常工作两侧既有 STATE.md 单元测试通过CONTEXT.md的 STATE.md Document Module 条目补一句注明事实源文件路径。回滚revert 分支即可从 git 历史重新导入被删的 CJS 内容即可恢复原手工同步形态无外部消费者受损。Phase 2 — Configuration Module关闭 #3523 这一类 bug为何第二这正是触发本工作的模块是杠杆最高的漂移面也用来检验模式能否从纯变换模块扩展到「消费数据 manifest」的模块。范围先在CONTEXT.md增加 Configuration Module 条目定义「Module owning config load, legacy-key normalization, defaults merge, and explicit on-disk migration for.planning/config.json」把CONFIG_DEFAULTS、VALID_CONFIG_KEYS、DYNAMIC_KEY_PATTERNS、RUNTIME_STATE_KEYS抽取到两个数据 manifestsdk/shared/config-schema.manifest.json与sdk/shared/config-defaults.manifest.json先例sdk/shared/model-catalog.json在sdk/src/configuration/index.ts写 Configuration Module 源导入两份 manifest 并导出loadConfig、normalizeLegacyKeys、mergeDefaults、migrateOnDisk写生成器与 freshness 检查把bin/lib/core.cjs:loadConfig220–243、434–449、485 行与bin/lib/config.cjs里的内联实现替换为薄 Adapter删除内联CONFIG_DEFAULTS、core.cjs:444-449的误报警告与重复的_deepMergeConfig把sdk/src/config.ts:mergeDefaults192–218 行替换为对新 Module 的 re-export用四种 legacy-key 归一化的 fixture 矩阵扩展 golden parity 集成测试。验收标准两个 CJS 文件不再含本地CONFIG_DEFAULTS/VALID_CONFIG_KEYS字面量均经生成模块从 manifest 加载#3523 fixture 矩阵在 CJS 与 SDK 两侧都通过、误报警告消失四种 legacy-key 形态顶层branching_strategy、顶层sub_repos、multiRepo: true、顶层depthgolden parity 全绿#3523 关闭并反向引用本阶段。Phase 3 — Workstream Inventory Builder 剩余手工同步对为何第三Phase 1 证明模式适用于纯变换、Phase 2 证明适用于数据 manifest 支撑的逻辑Phase 3 则把模式推广到审计暴露的其余手工同步对。Workstream Inventory Module 是主打案例因为它需要Builder/Reader 拆分——投影逻辑是纯的、可共享但目录遍历在 CJS 侧合理用同步、SDK 侧合理用异步这是所有「纯逻辑 I/O 混杂」配对模块的统一模式。范围在sdk/src/workstream-inventory/builder.ts写 Builder 源纯函数输入目录项列表 每个 workstream 的 STATE.md 文本 plan-scan 结果返回类型化投影WorkstreamPhaseInventory/WorkstreamInventory不做任何 fs 读取写生成器产出get-shit-done/bin/lib/workstream-inventory-builder.generated.cjs与sdk/src/query/workstream-inventory-builder.generated.ts把bin/lib/workstream-inventory.cjs重构为同步 Reader Adapterfs.readdirSync 读取 STATE.md 后调用 Builder把sdk/src/query/workstream-inventory.ts重构为异步 Reader Adapter审计其余疑似配对frontmatter.cjs↔frontmatter-mutation.ts、plan-scan.cjs↔ SDK 对应物判断可否纯变换共享对可共享者在本阶段套用 Builder 模式对结构性重复者如路由表、返回形态不同的 sync/async在阶段 issue 中记录决策并延后。Phase 4 — Project-Root Resolution Module范围在CONTEXT.md增加 Project-Root Resolution Module 条目接口为findProjectRoot(startDir)、findEffectiveRoot(startDir, options)源在sdk/src/project-root/index.ts纯函数注入 fs 探针或直接用两运行时都具备的同步node:fs替换bin/lib/core.cjs:74-140与sdk/src/helpers.ts:497-630为薄 Adapter扩展四种配置的 parity 测试独立项目、带planning.sub_repos的 monorepo、legacymultiRepo: true、深层嵌套。验收标准findProjectRoot在源形式上只定义一次两侧都导入生成模块上述四种配置的 parity 测试通过。Phase 5 — CJS Command Router Adapter委托给 SDK runtime bridge为何第五Phase 1–4 收缩的是共享逻辑的漂移Phase 5 收缩的是并行逻辑的漂移——即 CJS 侧每侧的 state/verify/init/phase/roadmap/validate handler 实现。Phase 5 之后任何经gsd-tools运行的规范命令都在进程内执行与gsd-sdk query相同的 SDK handler无子进程跳跃接缝成为真正的墙。范围为 CJS 调用方暴露QueryRuntimeBridge的同步友好入口——今天的QueryRuntimeBridge.execute()是异步的bridge 将新增executeForCjs(input) → { exitCode, stdoutChunks, stderrLines }同步包装器在deasync或受控runUntil语义下运行 dispatch工具链选择在 Phase 5 issue 中定夺若同步桥不可行回退到 worker 通道上的Atomics.wait——绝不允许gsd-sdk子进程把bin/lib/*-command-router.cjs中每个规范族 handler map 替换为生成的 delegate emitter按子命令调用executeForCjs({ canonical, argv, env, cwd })并经既有 CJS 输出 Adapter 写出结果对每个规范命令族按state.*、verify.*、phase.*、phases.*、validate.*、roadmap.*、init.*、frontmatter.*、config.*加sdk/src/query/command-manifest.non-family.ts所列非族命令每族一个子 PR 迁移、合入前跑 golden parity 矩阵为已迁移各族删除或缩减 CJS handler 文件state.cjs、verify.cjs、init.cjs、phase.cjs、phases.cjs、validate.cjs、roadmap.cjs、milestone.cjs、frontmatter.cjs、config.cjs写路径、plan-scan handlers 等Phase 1–4 的纯变换 Shared Module 不动只替换各族 handler 入口点CJS-only 模块 handlers 保持进程内实现不进规范族注册表、不走 SDK runtime bridge扩展sdk/src/golden/golden.integration.test.ts验证 manifest 中每个规范命令在gsd-tools family subcommand已委托与gsd-sdk query canonical间 exit code stdout chunks stderr lines 完全一致。验收标准executeForCjs以阶段 issue 定夺的同步语义交付manifest 中每个规范命令族都经executeForCjs路由CJS-only 命令继续走既有 handler每个 CJS handler 文件不再含命令特定逻辑仅 delegate 接线或被删除golden parity 矩阵对每个规范命令验证gsd-tools与gsd-sdk输出等价调用gsd-tools的 workflow markdown 无回归单次gsd-tools调用的子进程开销不增加bridge 是进程内的不是gsd-sdk子进程。按族回滚每族的 PR 独立可回退未迁移族的 CJS handler 文件仍在 git 历史中某族委托一旦回归就 revert 该族 PR 并恢复 CJS handler。Phase 6 — 强制加固 回顾范围写scripts/lint-shared-module-handsync.cjs——grepget-shit-done/bin/lib/name.cjs与sdk/src/query/name.ts或sdk/src/name.ts中「两侧都非*.generated.*」且不在显式 allow-list 上的配对allow-list 记录合作兄弟型例外如实现结构不同的路由文件核验 Phase 1–4 每个 Shared Module 都接入了 freshness-check 工作流核验 Phase 5 golden parity 矩阵覆盖每个规范命令族为每个 Shared Module 事实源目录sdk/src/module/**、sdk/shared/*.manifest.json与 Phase 5 边界sdk/src/query-runtime-bridge.ts增加 CODEOWNERS 规则架构组评审回溯反复 bug 清单#1535…#3523在docs/agents/cjs-sdk-seam.md中逐条记录五层强制handsync lint、freshness check、manifest 数据隔离、逐模块漂移 lint、runtime-bridge 委托中哪一层能挡住它写docs/agents/cjs-sdk-seam.md作为面向 CONTRIBUTING 的「新增 Shared Module / 新增规范命令」指南。验收标准lint 在 CI 运行并能拦截故意引入的回归 PR每个 Shared Module 出现在 freshness-check 步骤触碰bin/lib/*或sdk/src/query/*的每个 PR 都跑 golden parity 矩阵CODEOWNERS 就位回顾文档提交任何重新引入 #3523 反模式或绕过规范命令 runtime-bridge 委托的 PR 都无法合入。Done when完结判据#3524在以下条件满足时关闭六个阶段全部交付、每阶段以其合并的 PR 关闭各自阶段 issue且 Phase 6 回顾确认历史漂移 bug 清单中的每一个都会被五层强制之一挡住。跨阶段关注点兼容性、性能与交付约束向后兼容CJS 公开 CLI 面gsd-tools subcommand不变。flag、exit code、stdout 形态全保留。每个阶段都在既有 Module Interface 之后替换内部实现外部契约由既有 golden parity 套件加新 fixture 矩阵钉死。性能全程无子进程开销。生成出的.cjs是require-able 的 CommonJS 模块SDK 直接消费 TS 源所有阶段合计的模块加载成本为每次require≤ 10 ms。Phase 5 特别保住进程内模型executeForCjs在 CJS dispatcher 所在的同一 Node 进程内跑 SDK handler不调用gsd-sdk子进程同步桥接每次调用相对原直接 CJS handler 调用仅增加至多几微秒。构建/安装管线影响每个生成器在开发机构建期运行freshness 检查在 CI 跑无运行时生成发布包已含bin/与sdk/dist/生成的.cjs与command-aliases.generated.cjs一样提交进仓库安装流程不变、无安装期代码生成npm run gen:module依既有先例调用生成器。主要风险PRD 用风险表给出含生成输出在提交间漂移、TS 源用了 CJS 无法表达的语法、_deepMergeConfig语义微妙变化、migrateOnDisk升级时静默改变用户可见行为、CODEOWNERS 拖慢架构组响应、Phase 3 审计 scope 膨胀、Phase 5 同步桥机制deasync是 C 绑定、Atomics.wait需 Worker、把所有 handler 改同步体量太大无干净形态High用 Phase 5 spike 先决、Phase 5 族迁移回归 CJS 输出、启动时间因 bridge 预载更多 handler 而变长用懒加载 time gsd-tools state load前/后对比中位延迟回归 20 ms 即打回该族 PR。从纸面到现实当前仓库中的实现证据PRD 的价值最终要落到代码。当前仓库中六阶段的产物大多已实体化可作为阅读 PRD 时的对照生成器家族sdk/scripts/下除 gen-command-aliases.ts 外还存在gen-state-document.ts、gen-configuration.mjs、gen-project-root.mjs、gen-workstream-inventory-builder.mjs等一一对应 Phase 1–4 的模块freshness 门禁sdk/scripts/check-command-aliases-fresh.mjs、check-state-document-fresh.mjs、check-configuration-fresh.mjs、check-project-root-fresh.mjs、check-workstream-inventory-builder-fresh.mjs、check-workstream-name-policy-fresh.mjs均已就位生成产物get-shit-done/bin/lib/下可见state-document.generated.cjs、configuration.generated.cjs、project-root.generated.cjs、workstream-inventory-builder.generated.cjs、plan-scan.generated.cjs等CJS 侧已通过生成文件消费共享逻辑数据 manifestsdk/shared/下已存在 config-schema.manifest.json、config-defaults.manifest.json 与先例 model-catalog.jsonPhase 6 的 lint 与 allow-listscripts/lint-shared-module-handsync.cjs 与 scripts/shared-module-handsync-allowlist.json 已在仓库中印证「任何新增手工同步对需显式 allow-list 且经 CODEOWNERS 评审」的强制CONTRIBUTING.md 的 CJS↔SDK seam 段也要求动手前先读docs/agents/cjs-sdk-seam.mdPhase 5 的 runtime bridgeSDK 侧存在 query-runtime-bridge.ts 及sdk/src/runtime-bridge-sync/含 worker 与索引与 PRD 中「同步桥接或Atomics.waitworker 通道回退」的备选路径相符。需要说明的是从源码结构只能确认这些文件已存在每条文件是否已完全达到 PRD 对应验收标准例如某族 handler 是否已完全 delegate需逐文件对照验收清单核查不可一概而论。结语PRD 是 GSD 的「防漂移契约起点」对 GSD 这类双运行时CJS CLI TypeScript SDK共存的中型仓库而言docs/prd/不只是文档堆放的目录它配合「issue 先行 issue# 命名」的治理把「先论证 why、再规划 how 的落地路径、最后才写代码」变成强制流程#3524 这份参考 PRD 则示范了如何把一次大型结构性迁移切成六个可独立交付/回滚的阶段并用「单一事实源 生成产物 freshness 检查 handsync lint runtime-bridge 委托」五层机制钉死漂移回归。阅读时建议按 docs/prd/README.md → docs/prd/3524-cjs-sdk-hard-seam.md → docs/adr/3524-cjs-sdk-hard-seam.md → sdk/scripts/ 的顺序走一遍即可完整看到 GSD「PRD 定义路线、ADR 记录决策、代码兑现验收」的工程闭环。【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门