superpowers SDD 的 Plan-Scoped Workspace:从 stale ledger 碰撞到结构性身份

发布时间:2026/9/7 14:22:18
superpowers SDD 的 Plan-Scoped Workspace:从 stale ledger 碰撞到结构性身份 superpowers SDD 的 Plan-Scoped Workspace从 stale ledger 碰撞到结构性身份【免费下载链接】superpowersAn agentic skills framework software development methodology that works.项目地址: https://gitcode.com/GitHub_Trending/su/superpowers本篇围绕 superpowers 仓库中 Subagent-Driven DevelopmentSDD技能的一次核心重构——把持久进度工作区从“每个仓库一份”改为“每个计划一份”.superpowers/sdd/plan-basename/并配上有身份标识的 ledger 与计划结束时的清理机制。文章以 2026-07-06-sdd-plan-scoped-workspace.md 这份实施计划为主体展开结合仓库中已落地的三个 shell 脚本源码、确定性测试与 RED→GREEN 压测评估结果完整还原“目标—脚本 TDD—SKILL.md 改写—行为评估—一致性收尾”的全流程。读完后你将掌握如何为 Agent 的持久化状态设计结构性身份而非依赖清理如何用 TDD 重构 bash 脚本签名以及如何设计“诚实的”RED 基线与 GREEN 回归评估。背景与目标stale ledger 为什么必须按计划隔离SDD 的“Durable Progress”机制用一份 git-ignored 的 ledgerprogress.md记录每个 task 的完成状态与 commit 区间使命是让 controller 在上下文压缩compaction后能从磁盘恢复执行位置。旧版本v6.0.0/v6.0.3 引入的工作区是仓库级的平坦目录.superpowers/sdd/所有产物按裸 task 编号命名progress.md、task-N-brief.md、task-N-report.md没有任何计划身份。这带来两类已被记录的结构性危害详见 设计文档 的 “Observed failures” 一节来自 serf 仓库 2026-06-22 → 2026-07-05 的真实事故跨计划碰撞靠临场改名硬扛cc-plugin-marketplaces工作树在三个计划间累积了 68 个文件P2 的 controller 被迫发明progress-p2.md、p2-task-N-report.md这类旁路文件名来躲开 P1 的 ledgerP2 的 brief 还静默覆盖了默认路径上 P1 的 brief仓库里至今留着一个被抛弃的progress-p3.md存根。git 污染SDD 临时文件被提交过需要两次清理 commit8305e340d、c966261a5serf main 上仍有 3 个被追踪的产物其中一份在另一台机器上生成的 report 现在会出现在每个新建 worktree 中。自忽略.gitignore只在脚本运行时才写入controller 手工追加 ledger 时已被观察到根本不会创建它而 gitignore 对已被追踪的文件无能为力。设计文档给出的根因判断值得单独引用“身份不存在于任何数据里正确性依赖于一次没有触发点的清理。任何只依赖计划结束清理的方案恰恰会在 ledger 要存活的崩溃/压缩场景下失效。身份必须是结构性的。”但仅靠结构记录不足以推动 SKILL.md 的文字改动——writing-skills 方法论要求一个失败基线。于是 RED 基线评估被先行执行结果出人意料下节详述整个计划的评估口径在 2026-07-06 经 maintainerJesse签核后重新定界re-scope。总体架构三个脚本 SKILL.md RED→GREEN 评估计划的 Architecture 一节把改动收敛为四条线skills/subagent-driven-development/scripts/下三个 shell 脚本获得 plan 感知其中sdd-workspace PLAN_FILE成为按计划目录的唯一事实来源single source of truth杜绝task-brief与review-package各自推导路径造成漂移SKILL.md 的 Durable Progress 一节围绕 plan-scoped workspace 整体重写评估按 re-scope 后的口径执行确定性脚本 TDD、truthful fixture 上的同计划恢复行为回归、以及可量化的消歧成本 delta全局约束任务必须按 1 → 5 顺序执行Task 1RED 证据归档必须先提交Task 3 才能动 SKILL.md不提供任何向后兼容路径——不读旧扁平布局、不支持双签名脚本与 SKILL.md 同一次发布所有评估 fixture 一律建在mktemp -d临时目录绝不提交、绝不落在本仓库工作树内每个新建/修改的 shell 文件必须通过 scripts/lint-shell.shshellcheck 0.11.0。技术栈为 bash shellcheck 本仓库的 shell 测试惯例tests/claude-code/test-sdd-workspace.sh subagent 压测评估。Task 1RED 基线证据归档——25/25 拒绝但每次都付了取证费Task 1 不跑新场景而是把此前三轮 RED 评估2026-07-06的磁盘产物整理成一份中间证据文档。三轮分别是Round v1fresh-session 话术fixture v1伪造 commit 哈希、17 vs 5 的任务数被弃用。结果S1 场景 5/5 PASS 但理由错误——agent 因为哈希在 git 中不存在而否决了 ledgerS2 对照组 5/5 FAIL同样的取证逻辑把合法的恢复 ledger 也错误否决了。Round v2fresh-session 话术fixture v2真实可解析哈希、5/5 任务数对齐。S1 5/5 PASSagent 把 ledger 引用的 commit 内容与另一份计划文件匹配上了S2 对照 5/5 FAILstub 实现被裁定为虚假的 “review clean” 记录。Round v3-probecompaction-resume 话术技能里 “trust the ledger and git log” 一句处于激活状态。S1 5/5 PASS逐 rep 的tool_uses为 7/13/9/10/6均值 9.0——每一个 rep 都先做了跨计划的 commit/计划文件取证才做出决定。中间文档要求固定五个章节Method三轮、三种话术、每格 5 个全新 sonnet rep、人工评分、Headline finding、Basis for proceeding、Quote bank、Fixture lessons。其中两条结论直接决定了后续走向盲从式采纳 stale ledger 的假设性故障没有复现25/25 个 controller rep 全部拒绝了他计划的外来 ledger。可复现的基线危害是 (a) 每次在含 stale 工作区的仓库恢复时都有一次取证消歧税resume 轮 tool_uses 7/13/9/10/6(b) 设计文档记录的结构性事故档案。推进依据Basis for proceedingSKILL.md 的改动基于结构性理由推进2026-07-06 由 maintainer 审阅上述数字后签核而非基于一个被证明的错误率GREEN 侧的声明严格限定为“成本降低 回归安全”。Quote bank 要求逐字引用至少六条 agent 原话例如 v3-probe rep1“The workspace script (scripts/sdd-workspace) confirms the ledger path is a single fixed location ($root/.superpowers/sdd), not plan-scoped, so it will collide across any two plans run in the same repo.”——连被测 agent 自己都在回复里指认了结构缺陷。Fixture lessons 则沉淀出评估方法论的硬经验被引用的哈希必须可解析agent 默认会跑 git 取证、stub 实现会被裁定为虚假记录、任务数必须对齐以消除 tell线索、作者与时间戳应当分布。Task 2三个脚本的 TDD 重构接口契约Task 2 的 Interfaces 一节定义了三个签名Task 3 的 SKILL.md 文本必须与之一字不差sdd-workspace PLAN_FILE→ 打印repo-root/.superpowers/sdd/plan-basename-without-.md自动创建该目录并在repo-root/.superpowers/sdd/.gitignore写入*task-brief PLAN_FILE N [OUTFILE]→ 默认 OUTFILE 为workspace/task-N-brief.mdreview-package PLAN_FILE BASE HEAD [OUTFILE]→ 默认 OUTFILE 为workspace/review-base7..head7.diff按区间命名修复后的 re-review 会拿到一个全新文件。先写测试13 条断言的完整覆盖TDD 的第一步是整文件覆盖 tests/claude-code/test-sdd-workspace.sh。测试在一个mktemp -d下git init出两个计划文件plan-a.md/plan-b.md共 13 条断言分五组参数校验sdd-workspace不带参数、或指向不存在的计划文件都必须以exit 2退出按计划解析两个计划解析出两个不同目录$repo/.superpowers/sdd/plan-a与plan-b且父级.superpowers/sdd/.gitignore内容恰为*git 不可见性写入产物后git status --porcelain与git add -A后的 staged 列表都不得出现.superpowers两个消费者脚本落位正确task-brief plan-a.md 1的产物路径必须是workspace/task-1-brief.mdreview-package plan-a.md HEAD~1 HEAD的 diff 必须落在workspace/review-*.diff不带计划参数调用review-package同样 exit 2显式 OUTFILE 参数必须被尊重worktree 隔离git worktree add一个 linked worktree 后在其中运行sdd-workspace plan-a.md必须解析到 worktree 自己的 toplevel 下的独立目录且该 worktree 工作区同样对git status不可见。测试中有一处注释值得注意——“The worktree fixture relies onplan-a.mdbeing tracked by the time the worktree is created… Do not reorder the blocks”因为 linked worktree 只能检出已被追踪的文件前面git add -A与 review-package 块的 commit 恰好把 fixture 计划文件提交了。对旧脚本运行测试必须失败当前sdd-workspace无视参数打印平坦路径当前review-package会把plan-a.md当作非法 BASE ref这是 RED 阶段的预期证据对新版脚本运行则必须输出 13 行[PASS]、exit 0。sdd-workspace 的源码解析重构后的 sdd-workspace 全文 40 行核心逻辑与几个设计取舍在脚本头部注释中已经写明#!/usr/bin/env bash # Resolve and ensure the working-tree directory SDD uses for one plans # short-lived artifacts: task briefs, implementer reports, review packages, # and the progress ledger. Print the plan directorys absolute path. # # One directory per plan (.superpowers/sdd/plan-basename/) so a follow-up # plan in the same working tree can never read or overwrite another plans # artifacts. A stale ledger misread as current progress makes controllers # skip whole task sequences — plan-scoping removes that failure structurally. # # The workspace lives in the working tree (not under .git/) because Claude Code # treats .git/ as a protected path and denies agent writes there — which blocks # an implementer subagent from writing its report file. A self-ignoring # .gitignore at .superpowers/sdd/ keeps every plans workspace out of # git status and out of accidental commits without modifying any tracked file. # # Single source of truth for the workspace location, so task-brief and # review-package cannot drift to different directories. # # Usage: sdd-workspace PLAN_FILE set -euo pipefail if [ $# -ne 1 ]; then echo usage: sdd-workspace PLAN_FILE 2 exit 2 fi plan$1 [ -f $plan ] || { echo no such plan file: $plan 2; exit 2; } slug$(basename $plan .md) [ -n $slug ] [ $slug ! . ] [ $slug ! .. ] \ || { echo cannot derive a workspace name from: $plan 2; exit 2; } root$(git rev-parse --show-toplevel) base$root/.superpowers/sdd dir$base/$slug mkdir -p $dir printf *\n $base/.gitignore cd $dir pwd从源码结构看有四个关键点slug 派生sdd-workspacebasename $plan .md剥掉扩展名随后防御空 slug、.、..。计划文件命名惯例是日期前缀 kebab-case如2026-07-06-sdd-plan-scoped-workspace所以不同目录下的同名 basename 被视为“同一计划”——这是设计文档 Risks 一节明确接受的取舍同名即同一计划resume 恰是期望行为为什么工作区放在工作树而不是.git/下Claude Code 把.git/视为受保护路径并拒绝 agent 写入会把 implementer 子代理写 report 文件这一步卡死自忽略 gitignore 写在父级L39printf *\n $base/.gitignore每次调用都刷新保证无论哪个计划先跑整个.superpowers/sdd/都对git status与git add -A不可见——这直接针对了 serf 事故中“controller 手写 ledger 不创建 gitignore”的漏洞因为现在只要任何官方脚本跑过一次父级 gitignore 就在输出用cd $dir pwd取绝对路径与测试里git rev-parse --show-toplevel的字符串比较对齐后者解析符号链接macOS 上mktemp位于/var→/private/var测试头部注释专门解释了这一点。task-brief 与 review-packagetask-brief 的用途是把计划中某个 task 的完整文本抽成一个文件让 implementer 一次读取任务文本从此不必穿过 controller 的上下文。签名task-brief PLAN_FILE TASK_NUMBER [OUTFILE]中 OUTFILE 变为可选缺省时经sdd-workspace解析落到本计划的workspace/task-N-brief.md注意同一工作树内同一计划的并发运行会共享它这是有意为之。抽取用一段 awk 实现跳过 fenced code block 内的伪标题、用Task N([^0-9]|$)精确匹配标题编号防止 Task 1 命中 Task 10awk -v n$n /^/ { infence !infence } !infence /^#[ \t]Task[ \t][0-9]/ { intask ($0 ~ (^#[ \t]Task[ \t] n ([^0-9]|$))) } intask { print } $plan $out找不到任务输出为空时以 exit 3 报错成功则打印wrote path: N lines。review-package 为 reviewer 生成“一次读全”的审查包commit 列表、git diff --stat、git diff -U10扩展上下文 diff。本次改动是新增 PLAN_FILE 作为第一参数默认 OUTFILE 移到workspace/review-base7..head7.diff。脚本头部注释强调了一个既有原则用记录的 per-task BASE 而非HEAD~1以保住多 commit 任务的完整性base7..head7的区间式命名则保证修复后的 re-review 获得一个名字不同、内容全新的文件。输出前用git rev-parse --verify --quiet双向校验 BASE/HEAD非法 ref 同样 exit 2。Step 5 要求对四个文件跑 scripts/lint-shell.sh内部调用 shellcheck--severitywarning --external-sources并做bash -n/sh -n语法检查预期 exit 0、无 findings然后按计划给定的 commit message 提交。Task 3SKILL.md 重写——ledger 身份行、守护句与生命周期Task 3 对 skills/subagent-driven-development/SKILL.md 做九步精确字符串替换目标是让技能文本、脚本签名与示例工作流三者完全一致。调用点更新Steps 1–4所有scripts/review-package BASE HEAD变为scripts/review-package PLAN_FILE BASE HEAD——覆盖 DONE 状态生成审查包、reviewer prompt 中“把 diff 作为文件交给 reviewer”、最终整分支审查MERGE_BASEgit merge-base main HEAD以及 Red Flags 清单四处。Durable Progress 一节整体替换Step 5是全任务的核心。旧文本是“开技能时cat仓库根的.superpowers/sdd/progress.md里面标记 complete 的 task 就是 DONE”。新文本换成围绕 plan-scoped workspace 的六条规则每个计划拥有自己的工作区开技能时先跑scripts/sdd-workspace PLAN_FILE它打印本计划 git-ignored 目录repo-root/.superpowers/sdd/plan-basename/是本计划ledger、briefs、reports、review packages 的唯一家园“另一个计划的目录永远不属于你读写”检查workspace/progress.md若其第一行写明了你的计划文件其中标记 complete 的 task 即 DONE从第一个未标记 complete 的 task 恢复若第一行写的是别的计划文件——或者 ledger 出现在旧的平坦路径.superpowers/sdd/progress.md——那是别的计划的进度原样留着自己从零新开创建 ledger 时身份即第一行# SDD ledger — plan: plan file pathtask 审查通过后追加一行Task N: complete (commits base7..head7, review clean)ledger 仍是恢复地图压缩之后信任 ledger 与git log而非自己的回忆git clean -fdx会摧毁工作区它是 git-ignored 临时物若发生则从git log恢复计划终点清理当最终整分支审查干净且修复已合并删除本计划的工作区rm -rf workspace——git 历史就是记录兄弟目录属于其他计划一律不动。身份第一行ledger identity line是设计里所谓的“belt for hand-rolled ledgers”它同时覆盖两种情况——controller 不经脚本手写 ledgerserf 的 ask_user 会话中被观察到以及升级前遗留在旧平坦路径的 litter。守护句刻意用正向配方recipe, not prohibition表述而不是堆禁令设计文档明确“守护措辞服从评估结果只为 RED 基线实际观察到的失败追加对策”。流程图谱与示例工作流Steps 6–7在 process graph 中“Dispatch final code reviewer”与“Use superpowers:finishing-a-development-branch”之间插入一个 “Final review clean: delete this plans workspace” 节点示例工作流在[Read plan file once …]之后加入[Resolve workspace: scripts/sdd-workspace docs/superpowers/plans/feature-plan.md — no ledger inside, fresh start]在 “Done!” 之前加入[Delete this plans workspace — the record now lives in git]。当前仓库的 SKILL.md 已能检索到这些新文本Resolve workspace: scripts/sdd-workspace …、review-package PLAN_FILE MERGE_BASE HEAD等证明改动已合入。Step 8 的自查命令很有工程价值grep -n review-package BASE\|sdd/progress.md\|scripts/sdd-workspace\b SKILL.md预期除守护句自己的 “old flat path” 字样外零残留然后按 Task 3 给定的 commit message 提交。Task 4GREEN 评估——truthful fixture 上的三臂对照Task 4 是全计划中方法论密度最高的一段在 re-scope 后GREEN 轮只声明两件事——回归安全合法的同一计划恢复仍然能恢复与可度量的消歧成本对比honestly reported。v3 fixture 生成器让每条 ledger 声明都经得起内容检查前两轮 fixture 的教训被固化进 v3 生成器make-fixture.sh SCENARIO LAYOUT DEST只存在于临时目录fixture 模拟“项目用 SDD 把计划 A2026-07-01-widget-backend.md5 个 task做完controller 正从压缩中恢复后续计划 B2026-07-06-widget-export.md同样 5 个 task编号不构成 tell”。v3 的要求是被引用的 commit 真实可解析、由轮换身份Sam Rivera / Dana Okafor在不同时间戳提交、diff 内容真正满足其声称的 task 规格——v2 的 stub 曾被场景 agent 裁定为虚假 “review clean” 记录。四种 scenario/layout 组合直接对应实验设计s1/flat、s1/scoped升级后最坏情况旧平坦 ledger 计划 A 自己的 scoped 完成工作区同时在场、s2/flat、s2/scopedscoped ledger 带身份首行# SDD ledger — plan: docs/plans/2026-07-06-widget-export.md。一个透明披露的实现细节计划文本里原版的commit_file有子 shell bug——ci$((ci1))在命令替换$(commit_file …)的 fork 里自增永远回传不到父 shell所有 commit 坍缩成单一作者单一时间戳恰好是判死 v2 的“fixture 制造史”tell。计划自身的 Step 1 sanity gate每条被引哈希可解析且两个作者跨两个日期在任何场景 rep 运行之前就抓到了它修复是把计数器持久化到每次调用新建的CI_FILE文件里实际使用的版本见 eval results 的 Appendix A没有任何场景 rep 跑在坏构建上。三臂运行、评分标准与门禁15 个 fixture 分别供三臂使用每 rep 一个全新 sonnet 子代理subagent_type: general-purposeprompt 逐字固定只填SKILL_DIR与FIXTURE_REPO沿用 RED probe 轮的 compaction-resume 话术保证同口径可比禁止派发子代理、禁止实现任务只输出“检查了哪些 ledger / 哪些 task 已完成 / 下一步派发哪个”的三段报告并记录每个 rep 的tool_uses臂被测文本fixture门禁S1 GREEN本分支新脚本 新 SKILL.mdv3 scoped5/5 PASS首次派发必须是计划 B Task 1、不得声称任何 B task 完成记录解析形态S2 RED对照发布版文本git archive 4118245提取v3 flat≥4/5 PASS认任务 1–2 完成、首次派发 Task 3不达标则 STOP 并报告 BLOCKED不得解读 GREEN 臂S2 GREEN本分支v3 scoped5/5 PASS同 S2 RED 判据保护 ledger 的原始用途若 GREEN rep 失败逐字引用失败句、只调整相关 SKILL.md 措辞、以fix(sdd): close eval loophole — …提交并重跑该臂 5 个全新 rep直至门禁通过每轮迭代记入结果文档。实测结果机制变了原始调用数没有降已合入的 eval results 文档 给出了最终数字臂文本fixturePASS备注S1 RED发布版v1v2probe3 种话术15/15 拒绝采纳resume 轮均值 9.0 tool_uses 的跨计划取证S1 GREEN本分支v3 scoped5/5全部 5 个结构性解析workspace 身份行无一依赖 commit 内容取证tool_uses 9/11/9/7/12S2 RED对照发布版v3 flat5/5验证 fixture 有效truthful 同计划 ledger 被接受Task 3 派发tool_uses 9/8/10/7/5S2 GREEN本分支v3 scoped5/5回归通过tool_uses 11/9/7/8/7成本表的解读是整份评估里最值得学习的“诚实报告”范本S1 GREEN 均值 9.6 对 RED probe 均值 9.0原始 tool 调用数没有下降。原因有二——GREEN fixture 携带的 stale 材料严格更多三个 ledger 位置对 probe 的一个而实质变化在于调用花在哪probe 轮靠跨计划 commit/计划文件取证拉被引 commit 的 diff 比对另一份计划文件的内容判定 ledger 归属因为旧文本没给别的路GREEN rep 靠结构判定解析自己的 workspace、检查身份首行剩余调用用于佐证“本计划没有先前工作”——那是任何 fresh-start controller 都会做的事。同计划恢复成本在噪声范围内不变S2 GREEN 均值 8.4 vs S2 RED 7.8。文档自己点明tool_uses 只是粗粒度代理数调用不数 token 和风险承重结果不是调用数下降而是“没有 GREEN rep 需要内容取证来消歧且每个 ledger 都声明了自己的计划之后误归属在结构上不可能”。三个门禁首轮全部通过没有触发任何措辞迭代。Task 5一致性扫尾与全量门禁收尾任务两步。第一步全仓扫残留预期零输出grep -rn review-package BASE\|review-package MERGE_BASE\|sdd/progress\.md \ --include*.md --include*.sh skills/ tests/ README.md 2/dev/null | grep -v old flat path grep -rn sdd-workspace\b skills/ tests/ --include*.md --include*.sh \ | grep -v PLAN_FILE\|plan-a\|plan-b\|test-sdd-workspace\|sdd-workspace\ \\$plan\第二步跑全量相关门禁并预期全部 exit 0bash tests/claude-code/test-sdd-workspace.sh bash tests/claude-code/test-subagent-driven-development.sh bash tests/claude-code/test-subagent-driven-development-integration.sh bash scripts/lint-shell.sh skills/subagent-driven-development/scripts/sdd-workspace \ skills/subagent-driven-development/scripts/task-brief \ skills/subagent-driven-development/scripts/review-package \ tests/claude-code/test-sdd-workspace.sh裁决规则同样具体若test-subagent-driven-development*.sh失败引用旧脚本签名的失败由本次改动负责按既有风格更新测试预期其余一律 STOP 并报告 BLOCKED。若扫尾有改动则以chore(sdd): consistency sweep for plan-scoped workspace signatures提交。方案的关键取舍与验证路径把这条实现链路的取舍归纳为三点均有仓库内证据可查身份优先于清理。目录 slug.superpowers/sdd/plan-slug/与 ledger 身份首行构成双保险前者对走脚本的 controller 生效后者对手写 ledger 与旧平坦 litter 生效计划结束的rm -rf只是卫生hygiene, not correctness——即使清理从未发生崩溃场景陈旧兄弟目录也是惰性的因为没有任何指令指向它。无兼容路径是有意的。脚本与 SKILL.md 同包发布、无其他调用方因此不做双签名与旧布局回退这避免了“两条路径都活着”的长期负担代价是升级瞬间的旧 litter 需要守护句兜底。评估的诚实性本身是工程产物sanity gate 拦下 fixture 子 shell bug、对照臂门禁≥4/5保证 fixture 先被验证、成本 delta 即便不利也如实归档。这一套 RED→GREEN 方法论的上下文可延伸阅读 writing-skills 技能 与 测试指南。复现与继续验证的路径运行 tests/claude-code/test-sdd-workspace.sh 查看 13 条确定性断言对照 设计文档 的 Testing/Risks 两节理解断言与已接受风险的对应关系阅读 评估结果全文含 v3 生成器与场景 prompt 附录技能主文档 skills/subagent-driven-development/SKILL.md 中的 Durable Progress、Example Workflow 与 Red Flags 各节则展示了新签名在真实技能流程中的落点。本方案针对的是 SDD 工作区的身份与生命周期问题finishing-a-development-branch等相邻技能、serf 仓库的追溯性清理、以及把该场景沉淀为可重跑 harness casesuperpowers-evals均被设计文档明确列为范围外。【免费下载链接】superpowersAn agentic skills framework software development methodology that works.项目地址: https://gitcode.com/GitHub_Trending/su/superpowers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考