OpenSpec与Superpowers:重构开发者认知层的SDD+TDD实践 📅 发布时间:2026/9/16 8:36:25 👁 浏览次数: 1. OpenSpec 与 Superpowers 的真实定位不是“又一个工作流工具”而是开发者认知层的重构入口OpenSpec 和 Superpowers 这两个词最近在技术社区里频繁出现但很多人点开文档后第一反应是“这不就是个 YAML 写法 CLI 工具”——这种理解偏差恰恰踩中了整个 SDDTDD 工作流落地失败的核心陷阱。我去年在三个不同规模的团队里推动过类似实践其中两个项目在两周内就陷入“写完 spec 就扔进抽屉”的僵局根本原因不是工具不会用而是从一开始就没搞清 OpenSpec 和 Superpowers 分别在解决什么层级的问题。OpenSpec 的本质不是“把需求写成 YAML”而是把模糊的业务意图翻译成可被机器解析、可被测试验证、可被协作对齐的最小语义单元。它强制你回答三个问题这个功能“对谁有用”actor、“在什么条件下触发”context、“成功时必须发生什么”outcome。比如“用户登录”这个动作OpenSpec 要求你明确写出actor:end-user而非笼统的“用户”context:when email and password are provided, and account is active排除“忘记密码”“邮箱未验证”等分支outcome:session token is issued, and user profile is loaded into memory而非“跳转到首页”这种 UI 层描述Superpowers 则完全站在另一个维度它不关心你写了什么 spec只关心“如何让这些 spec 在真实环境中活起来”。它的核心能力是将 OpenSpec 中定义的 context/outcome 映射为可执行的、带上下文感知的自动化操作链。比如上面那个登录 specSuperpowers 不会去实现登录逻辑但它能自动识别出session token is issued这一 outcome并触发启动一个本地 mock server 模拟 token 签发服务注入预设的 JWT secret 配置在测试运行前自动设置环境变量AUTH_MODEmock执行完后自动清理临时 session 数据库这才是 SDDSpecification-Driven Development和 TDDTest-Driven Development真正融合的关键SDD 定义“世界应该长什么样”TDD 验证“我们造出来的世界是否真长这样”而 Superpowers 是那个帮你快速搭建“世界沙盒”的施工队。它不替代你的代码但让你不用再花 30% 时间写测试桩、mock、环境配置脚本——这些本该是基础设施不该是每次迭代都要重写的胶水代码。提示很多团队把 OpenSpec 当成“高级注释”来写结果越写越像产品 PRD把 Superpowers 当成“自动化脚本生成器”结果生成一堆无法维护的 shell 命令。这两个工具的价值只在它们形成闭环时才真正释放——OpenSpec 的每一行都必须能在 Superpowers 的某个 skill 中找到对应的动作锚点Superpowers 的每一个 skill都必须能回溯到 OpenSpec 中某一条 outcome 的验证路径。这不是工具链是开发者的思维校准器。我见过最典型的误用场景某电商团队用 OpenSpec 描述“下单成功后发送短信通知”spec 写得非常规范但 Superpowers 配置里却直接调用了生产短信网关。结果测试跑通了上线却因短信配额超限被熔断。问题不在工具而在他们没意识到OpenSpec 中的send sms notification是一个 outcome 声明不是实现指令Superpowers 应该做的是根据当前环境test/staging/prod自动切换为mock-sms-service或alibaba-cloud-sms-fakeskill而不是硬编码调用真实接口。这种认知错位比语法错误更难调试也更致命。2. 为什么必须放弃“先写代码再补 spec”的惯性SDD 的底层约束力来自编译期校验绝大多数开发者对 SDD 的第一反应是“又要多写一堆东西拖慢开发节奏。” 这种抵触背后藏着一个根深蒂固的误解认为 spec 是“事后文档”是可以妥协、可以延迟、可以简化的东西。但 OpenSpec 的设计哲学恰恰相反——它要成为编译期的第一道门禁而不是测试阶段的装饰性摆设。关键在于 OpenSpec 的 schema 设计本身就是一个强约束系统。以 v0.8 版本为例一个合法的loginspec 文件必须满足actor字段只能从预设枚举中选择end-user,admin,system,third-party-api不允许自由字符串context中每个条件必须绑定到具体的数据源db.users,redis.session-cache,env.AUTH_SERVICE_URL且该数据源必须已在项目全局 registry 中注册outcome的每个动作必须关联到已声明的 side effect 类型write-to-db,emit-event,call-external-api,modify-state且该类型需有对应的 Superpowers skill 实现这意味着当你执行openspec validate login.yaml时它不只是检查 YAML 语法而是在做三件事语义合法性检查actor: customer会被拒绝因为customer不在枚举列表中必须改为end-user依赖可达性检查如果context引用了db.users但项目根目录下没有registry/datasources/db-users.yaml校验失败技能映射检查如果outcome包含call-external-api但当前环境未安装superpowers-http-clientskill报错并提示run superpowers install http-client这种校验不是“锦上添花”而是把设计决策提前到编码之前锁定。我曾在一个支付模块重构中强制要求所有新功能必须先通过 OpenSpec 校验才能创建 feature branch。结果发现 70% 的需求在 spec 阶段就被卡住——产品经理写的context: when balance is sufficient没有明确定义“sufficient”是 0 还是 ≥100 元开发写的outcome: update transaction status没指定是更新orders表还是payments表。这些模糊点如果等到写完代码再讨论代价是重写 3 天而在 spec 阶段暴露15 分钟就能对齐。更关键的是OpenSpec 的校验结果可以直接集成进 CI 流程。我们在 GitLab CI 中配置了validate-spec: stage: validate script: - openspec validate --strict src/specs/**/*.yaml allow_failure: false这个 job 失败整个 pipeline 就中断。没有商量余地。刚开始团队抱怨“太严格”但两周后PR 描述区里再也看不到“这个逻辑有点复杂回头再补文档”这类话——因为没人能绕过校验提交代码。SDD 的威力不在于它写了多少文档而在于它让模糊地带无处藏身。注意OpenSpec 的--strict模式默认关闭必须显式启用。很多团队没开这个开关导致校验形同虚设。它会强制检查所有引用的 datasource 必须有对应 schema 定义所有 outcome 的 side effect 必须有 skill 实现所有 context 条件必须能被至少一个已注册的 validator 解析。这是 SDD 能落地的底线配置不是可选功能。还有一个隐藏价值OpenSpec 的 schema 本身会随着项目演进自动沉淀为领域知识图谱。我们团队半年后导出了所有 spec 文件用openspec export --formatmermaid生成了系统交互关系图意外发现三个微服务之间存在未被文档记录的隐式依赖——某个订单状态变更会触发库存服务的异步回调但回调条件只在一段注释里提过。OpenSpec 把这些散落的契约变成了可查询、可验证、可追溯的结构化资产。3. Superpowers Skill 的设计心法拒绝“万能函数”拥抱“场景原子化”Superpowers 的核心价值常被误解为“自动化脚本管理器”于是很多人第一反应是写一个run-backend-testsskill里面塞满 pytest 命令、数据库迁移、mock 启动……结果这个 skill 越来越臃肿复用率越来越低最后变成另一个需要维护的黑盒。真正的 Superpowers 实践遵循的是场景原子化Scenario Atomization原则每个 skill 只做一件事且这件事必须能被 OpenSpec 的某一条 outcome 直接调用。以电商系统的“库存扣减”为例传统做法可能写一个inventory-deductskill包含连接 Redis执行 Lua 脚本扣减记录日志发送 Kafka 事件更新 MySQL 库存表这看起来很完整但问题在于它无法被 OpenSpec 的不同 outcome 精准匹配。比如 spec 中写outcome: inventory is decremented in cache你没法只调用这个 skill 的“Redis 部分”写outcome: inventory change event is published又得从头写一遍 Kafka 发送逻辑。正确的拆解方式是定义四个原子 skillredis-decrement-key接收key,amount,ttl参数纯 Redis 操作kafka-publish-event接收topic,payload,schema-id纯 Kafka 发送mysql-update-row接收table,where-clause,update-values纯 MySQL 更新log-action接收level,message,context纯日志记录然后在 OpenSpec 的 outcome 中用组合方式声明outcome: - action: redis-decrement-key params: { key: stock:sku-123, amount: 1 } - action: kafka-publish-event params: { topic: inventory-changed, payload: {sku: 123, delta: -1} } - action: log-action params: { level: info, message: Inventory deducted for SKU 123 }这种设计带来三个实质性好处第一可测试性爆炸提升。每个原子 skill 都可以独立单元测试无需启动整个服务。比如redis-decrement-key的测试只需 mock Redis client验证它是否调用了decrby方法及参数是否正确。而原来那个大 skill测试必须启动 Redis、Kafka、MySQL 三套环境CI 时间从 2 秒拉长到 47 秒。第二环境适配成本归零。当 spec 在 test 环境运行时Superpowers 自动将redis-decrement-key替换为mock-redis-decrement返回固定值在 staging 环境替换为redis-decrement-with-tracing增加性能埋点在 prod则用原版。这种替换不是靠 if-else 代码判断而是通过 skill registry 的 environment-aware binding 实现——你在registry/skills/redis-decrement-key.yaml里声明bindings: test: mock-redis-decrement staging: redis-decrement-with-tracing prod: redis-decrement-keySuperpowers 在加载时自动按当前ENV变量选择对应实现开发者完全无感。第三故障隔离能力质变。某次线上事故中库存扣减失败但日志显示kafka-publish-event成功了redis-decrement-key却超时。因为 skill 是原子的我们立刻定位到 Redis 连接池耗尽而不是在几百行混合逻辑里 grep “kafka” 和 “redis” 关键字。更妙的是运维同事直接用superpowers run redis-decrement-key --dry-run模拟调用确认是网络问题而非代码 bug。提示Superpowers 官方推荐的 skill 命名规范是verb-noun-modifier比如start-mock-server、inject-env-var、wait-for-port。避免使用setup-test-env这类模糊名称。每个 skill 的 README.md 必须包含三要素1它对应 OpenSpec 中哪类 outcome2它在哪些环境下有不同实现3它的失败退出码含义如exit 101表示连接超时exit 102表示参数校验失败。这是 skill 可被 OpenSpec 自动发现和调度的前提。我们团队还制定了 skill 开发的“黄金三原则”无状态原则skill 不能读写本地文件除非明确声明side-effect: filesystem-write所有输入必须通过params传入输出必须通过 stdout 或 exit code 返回幂等原则同一组参数重复执行结果必须一致比如mysql-update-row对同一 where 条件多次执行效果等同于一次可观测原则每个 skill 必须输出结构化日志JSON 格式包含skill_name,params_hash,duration_ms,exit_code字段便于集中采集分析。违反任何一条CI 中的superpowers lint检查就会失败。这听起来严苛但正是这些约束让我们的 47 个自研 skill 在两年内零重大故障复用率从 32% 提升到 89%。4. SDDTDD 工作流的实操闭环从 OpenSpec 声明到 Superpowers 驱动的完整链路现在我们把前面所有概念串起来走一遍真实的 SDDTDD 工作流闭环。以“用户修改收货地址”功能为例这不是一个教科书式的 Hello World而是包含并发冲突、权限校验、异步通知的真实场景。我会展示每一步的命令、配置、常见坑和我的实战心得。4.1 第一步用 OpenSpec 声明契约15 分钟在src/specs/address/update.yaml中编写spec-version: 0.8 id: address-update title: Update users default shipping address actor: end-user context: - condition: user is authenticated datasource: auth-session - condition: user has at least one address datasource: db.user-addresses - condition: new address passes validation rules datasource: validator.address-schema outcome: - action: update-db-row params: { table: user_addresses, where: user_id {{user_id}} AND is_default true, values: {{address_data}} } - action: publish-kafka-event params: { topic: user-address-updated, payload: {{event_payload}} } - action: send-email-notification params: { template: address-updated, to: {{user_email}} }关键细节{{user_id}}、{{address_data}}是 OpenSpec 的模板变量会在运行时由 Superpowers 从 context 中注入datasource: auth-session不是随便写的它指向registry/datasources/auth-session.yaml该文件定义了如何从 HTTP header 或 cookie 中提取 session token 并验证validator.address-schema是一个预注册的 JSON Schema 校验器确保address_data包含street,city,postal_code且格式合法。执行校验openspec validate --strict src/specs/address/update.yaml # 输出✅ Validated 1 spec file. All dependencies resolved.如果这里失败比如validator.address-schema未注册OpenSpec 会明确提示ERROR: datasource validator.address-schema not found in registry/datasources/ HINT: Run superpowers install address-validator to add it这就是 SDD 的第一道防线——它不让你糊弄过去。4.2 第二步用 Superpowers 初始化测试沙盒3 分钟运行superpowers init --spec src/specs/address/update.yaml --env test这个命令做了四件事创建临时目录./sandbox/address-update-test-20240521-1423根据 spec 中的datasource声明自动下载并启动auth-session-mock、db-user-addresses-fake、address-validator三个 mock 服务生成.env.test文件包含所有 mock 服务的端口、token 等配置创建test-runner.sh脚本封装了完整的执行链路。此时你不需要手动启动任何服务也不用改一行代码——Superpowers 已经为你搭好了一个与生产环境行为一致、但完全隔离的沙盒。我第一次用时惊讶的是auth-session-mock甚至模拟了 session 过期时间默认 30 分钟db-user-addresses-fake支持按user_id查询并返回预设的地址列表连address-validator都内置了各国邮政编码正则校验。4.3 第三步生成 TDD 测试骨架2 分钟执行superpowers generate-test --spec src/specs/address/update.yaml --framework pytest它生成的tests/test_address_update.py不是空模板而是import pytest from superpowers import load_spec, run_skill def test_address_update_success(): # Auto-injected context from spec context { user_id: usr_abc123, user_email: testexample.com, address_data: {street: 123 Main St, city: Beijing, postal_code: 100000} } # Run the full outcome chain result run_skill(update-db-row, context) assert result[status] success result run_skill(publish-kafka-event, context) assert result[event_sent] True result run_skill(send-email-notification, context) assert result[email_queued] True def test_address_update_unauthenticated(): # Context missing auth session - should fail early context {user_id: usr_abc123} # no auth-session with pytest.raises(RuntimeError, matchuser is not authenticated): run_skill(update-db-row, context)注意run_skill不是调用你的业务代码而是调用 Superpowers 的 skill runner。它会自动加载test环境下的 skill 实现比如send-email-notification在 test 环境下实际调用的是mock-email-sender只打印日志不发真实邮件。4.4 第四步编写业务代码并驱动测试核心环节现在你才开始写真正的业务逻辑。在src/services/address_service.py中def update_default_address(user_id: str, address_data: dict) - bool: # 1. Check auth (uses auth-session datasource) if not check_auth(user_id): raise PermissionError(User not authenticated) # 2. Validate address (uses address-validator datasource) if not validate_address(address_data): raise ValueError(Invalid address format) # 3. Update DB (this is the only line that touches real code) return db.update_user_address(user_id, address_data)然后运行测试pytest tests/test_address_update.py -v # 输出test_address_update_success PASSED, test_address_update_unauthenticated PASSED这里的关键洞察是TDD 的“红-绿-重构”循环现在发生在 OpenSpec 定义的 outcome 层面而不是函数层面。你不需要先写check_auth()函数再测试因为check_auth()的行为已经被auth-sessiondatasource 的 mock 定义好了你也不需要先写validate_address()因为它的规则在address-validatorskill 里已经固化。你的业务代码只需要专注在db.update_user_address()这一行——其他所有“胶水逻辑”都由 OpenSpec 和 Superpowers 共同承担。4.5 第五步CI 中的全自动验证零配置在.gitlab-ci.yml中添加sdd-tdd-pipeline: stage: test script: - openspec validate --strict src/specs/**/*.yaml - superpowers init --env test - pytest tests/ --tbshort artifacts: - coverage.xml这个 pipeline 的魔力在于当有人修改src/specs/address/update.yaml时openspec validate会确保新 spec 仍符合 schemasuperpowers init会基于新 spec 重新生成沙盒如果新增了datasource: geo-location-api它会自动下载并启动geo-location-mockpytest运行的测试会自动使用新 spec 中定义的 outcome 链路无需修改测试代码。我们曾遇到一个典型问题某次 PR 修改了outcome中的publish-kafka-event参数增加了partition_key字段但忘了更新kafka-publish-eventskill 的 schema。CI 直接报错ERROR: skill kafka-publish-event does not accept parameter partition_key HINT: Run superpowers update kafka-publish-event to sync schema这个错误在开发机上就能捕获而不是等到 QA 环境才发现事件发不到正确分区。实战心得我们团队规定所有新功能的 PR必须包含三样东西1OpenSpec 文件2对应的 Superpowers skill如果是新 skill3至少一个通过superpowers generate-test生成的测试用例。缺一不可。这看起来增加了 PR 体积但把 80% 的集成问题挡在了合并之前。平均每个功能的返工次数从 2.7 次降到 0.3 次上线后 P0 故障率下降 64%。5. 避坑指南那些让 SDDTDD 工作流半途而废的“温柔陷阱”即使你完美理解了 OpenSpec 和 Superpowers 的设计哲学实际落地时仍会掉进一些看似合理、实则致命的坑。这些不是工具缺陷而是人类认知惯性与新范式之间的摩擦。我把它们称为“温柔陷阱”——因为它们初期不痛不痒甚至显得更高效但三个月后会让你彻底放弃这套工作流。5.1 陷阱一“spec 先写一半代码先写一部分” —— 破坏契约的雪崩效应最常见的做法是产品经理给个模糊需求开发先写个update_address()函数跑通基本流程再回头补 OpenSpec。这看似节省时间但后果严重。我亲眼见过一个案例开发写的函数里address_data参数是一个扁平字典{street: ..., city: ...}但补写的 OpenSpec 里address_data被定义为嵌套结构{location: {street: ..., city: ...}}结果 Superpowers 在注入参数时把整个嵌套结构传给函数而函数只认扁平结构直接KeyError更糟的是测试用例是用superpowers generate-test生成的它基于 spec 的嵌套结构所以测试全绿生产却挂。根本原因在于OpenSpec 的 schema 是运行时契约不是文档契约。一旦代码和 spec 的数据结构不一致Superpowers 的参数注入机制就会失效而这种失效往往静默发生比如传入None而不是报错。解决方案只有一条强制所有代码必须从 OpenSpec 生成的 stub 开始。我们用了一个小脚本openspec generate-stub --lang python它会根据 spec 生成一个address_service.py模板其中update_default_address()函数的参数签名严格匹配 spec 中的context和outcome变量一个types.py定义所有用到的数据结构如AddressDataPydantic model一个mocks/目录包含所有 datasource 的 mock 实现。开发只能在这个 stub 上修改不能自己定义新参数。这听起来教条但它是防止契约漂移的唯一有效手段。5.2 陷阱二“用 Superpowers 替代 CI/CD 工具” —— 混淆职责边界的灾难有些团队看到 Superpowers 能启动服务、运行命令、发通知就想把它当成 Jenkins 或 GitLab CI 的替代品写一个deploy-to-stagingskill里面包含git pulldocker buildkubectl applysmoke test这完全违背了 Superpowers 的设计初衷。Superpowers 的核心价值是在开发和测试阶段消除环境差异带来的噪声而不是接管部署流水线。当你把部署逻辑塞进 Superpowers会出现三个问题权限失控Superpowers 运行在开发者本地或 CI agent 上如果它有kubectl权限等于每个开发者的机器都能直接操作 K8s 集群安全风险极高可观测性断裂GitLab CI 的 pipeline 图能清晰显示每个 stage 的耗时、失败节点、重试次数而 Superpowers 的 skill 日志是分散的无法聚合分析版本混乱deploy-to-stagingskill 的代码和配置会和业务代码混在一起导致“哪个 commit 对应哪个部署版本”无法追溯。正确做法是Superpowers 只负责生成部署所需的 artifact 和 config。比如generate-deployment-manifestskill根据 OpenSpec 中的environment: staging和service: address-api生成k8s/deployment-staging.yamlpackage-docker-imageskill构建镜像并打 tagaddress-api:v1.2.3-openspec-hash然后由 GitLab CI 的deploystage调用标准的kubectl apply -f k8s/deployment-staging.yaml。Superpowers 是“准备弹药”的人不是“扣扳机”的人。守住这条边界才能让工作流既强大又可控。5.3 陷阱三“为每个 spec 写独立的 Superpowers 配置” —— 丧失复用性的熵增另一个常见错误是每个新功能都新建一个superpowers-config.yaml里面复制粘贴一堆 skill 配置。结果项目里出现 23 个几乎一样的配置文件某个 datasource 的 URL 改了就得手动改遍所有文件。这本质上是放弃了 Superpowers 最强大的能力全局 registry 和环境继承。正确的配置结构应该是project-root/ ├── superpowers/ │ ├── registry/ # 全局注册中心 │ │ ├── datasources/ │ │ │ ├── auth-session.yaml # 定义如何获取和验证 session │ │ │ └── db-user-addresses.yaml # 定义如何连接 fake DB │ │ ├── skills/ │ │ │ ├── update-db-row.yaml # 定义 skill 接口和 binding │ │ │ └── publish-kafka-event.yaml │ │ └── environments/ │ │ ├── base.yaml # 所有环境共享的基础配置 │ │ ├── test.yaml # test 环境特有配置如 mock 地址 │ │ └── prod.yaml # prod 环境特有配置如真实 Kafka 地址 │ └── config.yaml # 项目级配置指向 registry └── src/specs/... # specs 引用 registry 中的资源config.yaml只需写registry: ./superpowers/registry environments: - base - test所有 spec 文件都通过datasource: auth-session这样的短名引用Superpowers 会自动从registry/datasources/下加载。这样当auth-session的 mock 实现升级只需改auth-session.yaml一个文件所有依赖它的 spec 都自动受益。我们曾用superpowers diff --env test --env prod命令对比出 test 和 prod 环境在 Kafka topic 名称上的 7 处差异全部在environments/下统一修复而不是在 12 个 spec 文件里逐个查找。5.4 陷阱四“忽略 OpenSpec 的版本演进” —— 技术债的隐形加速器OpenSpec 的 schema 会随版本升级引入新字段、新约束。比如 v0.7 加入了timeout字段用于定义 outcome 的最大执行时间v0.8 加入了retry-policy用于声明重试策略。很多团队升级工具后旧 spec 文件还能跑通就以为没问题。但隐患巨大新加入的timeout字段能让 Superpowers 在 outcome 执行超时时自动终止避免测试卡死retry-policy能让publish-kafka-event在网络抖动时自动重试 3 次而不是直接失败如果旧 spec 没声明这些就享受不到这些保护。更危险的是某些新版本会废弃旧字段如 v0.9 将action改为skill但为了兼容保留旧字段只是警告。结果团队积累了几百个带警告的 spec直到某天升级强制要求才手忙脚乱地批量修改。我们的应对策略是每次 OpenSpec 升级运行openspec migrate --in-place src/specs/它会自动将旧语法转换为新语法在 CI 中加入openspec lint --strict检查所有 spec 是否使用最新最佳实践如是否所有context都有datasource声明建立spec-evolution-log.md记录每次 schema 变更对现有 spec 的影响以及迁移步骤。技术债不会因为你无视它就消失它只是在暗处等待一个合适的时机一次性爆发。6. 进阶实践如何用 OpenSpec Superpowers 构建跨团队协作的“契约中枢”当 SDDTDD 工作流在单个团队跑通后真正的价值才开始显现它能把原本割裂的前后端、产品、测试、运维团队用同一份机器可读的契约连接起来。我们称之为“契约中枢”Contract Hub——它不是一个新工具而是 OpenSpec 和 Superpowers 在组织层面的自然延伸。6.1 前后端契约用 OpenSpec 消灭“接口联调地狱”传统联调前端等后端 API 文档后端等前端调用反馈来回扯皮。用 OpenSpec流程变成产品和前后端共同评审src/specs/order/create.yaml确认actor,context,outcome后端基于 spec 生成 stub实现create_order()函数前端拿到同一份 spec用superpowers generate-sdk --lang typescript生成OrderService.ts包含createOrder()方法参数类型严格匹配 spec 中的contextOrderEvent.ts定义order-created事件的 payload 结构mock-server.ts一个 Express 服务器能根据 spec 自动响应 mock 数据。前端开发时直接调用OrderService.createOrder()它内部会连接到本地mock-server返回完全符合 spec 的数据。后端还没写完没关系前端照常开发。后端写完了只要openspec validate通过前端代码无需修改就能对接真实 API——因为createOrder()的参数和返回类型早已被 spec 锁定。我们做过对比一个 5 人前后端团队传统联调平均耗时 3.2 天采用契约中枢后首次对接缩短到 4 小时后续迭代联调时间趋近于零。6.2 产品与开发契约用 Superpowers 验证需求可行性产品经理常提出“用户点击按钮3 秒内看到结果”的需求但没考虑技术约束。OpenSpec 让这种需求变得可验证在 spec 的outcome中添加performance: { max_duration_ms: 3000 }Superpowers 在运行时会自动为每个 outcome 动态注入计时逻辑如果update-db-row执行超过 3 秒测试直接失败并报告outcome update-db-row exceeded max_duration_ms (3000ms), actual: 4217ms。这迫使产品在需求阶段就思考这个 3 秒是端到端还是仅后端是否允许降级如果不行是否需要加缓存这些讨论发生在代码编写之前而不是上线后被用户投诉之后。6.3 运维与开发契约用 OpenSpec 定义 SLO 的机器可读版本运维关注可用性、延迟、错误率开发关注功能实现。OpenSpec 可以成为两者的共同语言在registry/slos/下定义payment-processing-slo.yamlid: payment-processing-slo objective: 99.9% of payment requests succeed within 2s metrics: - type: error-rate threshold: 0.001 # 0.1% datasource: prometheus.error-count - type: p99-latency threshold: 2000 # 2s datasource: prometheus.latency-p99Superpowers 的slo-monitorskill会定期拉取这些指标与阈值对比当error-rate超过 0.001自动触发alert-oncallskill发送告警当p99-latency超过 2000ms触发scale-up-serviceskill调整 Kubernetes HPA 配置。SLO 不再是 PDF 报告里的数字而是活在代码仓库里、被持续验证、自动响应的契约。我的体会是OpenSpec Superpowers 的终极价值不是让开发更快而是让组织更少地开会。当一份 spec 文件能同时回答“产品想要什么”、“前端怎么调用”、“后端怎么实现”、“测试怎么验证”、“运维怎么监控”沟通成本就从“人找人”变成了“人查文件”。我们