OpenSpec OPSX:用语义规范驱动可执行工作流

1. 这不是又一个“流程编排工具”:OpenSpec OPSX 对 SDD 的底层重定义

你有没有过这种体验:写完一份需求文档,转头就发现开发同事盯着它发呆——不是看不懂,而是“这文档里哪句是能直接跑起来的逻辑?”;或者,测试同学拿着 BDD 场景用例来问:“这个‘当用户点击提交按钮且邮箱格式不合法时,应显示红色提示’,到底是前端校验、后端拦截,还是两者都要?谁负责触发 UI 变化?”;更常见的是,产品上线后,运营突然说“我们想把注册流程里的短信验证码环节,替换成微信一键登录”,技术团队一查代码,发现这个判断逻辑散落在三个服务、四个配置文件、两个前端组件里,改一处,漏三处,灰度发布当天凌晨三点还在回滚。

这不是协作问题,是 规范与执行之间存在不可弥合的语义鸿沟 。SDD(Specification-Driven Development,规范驱动开发)本意是让业务语言成为系统骨架,但过去十年,它几乎等同于“写更多文档+更多会议+更多对齐”。OpenSpec OPSX 的出现,不是给这个老问题加个新 UI,而是从根上把“规范”这个词重新焊死在可执行、可验证、可演进的工程基座上。它不替代 BDD 或 TDD,而是让 BDD 的 Given-When-Then 能直接变成 API 契约,让 TDD 的测试用例能自动反向生成 stub 服务,让产品经理写的“用户点击按钮后,3 秒内弹出成功 toast,并同步更新数据库和发送站内信”这句话,本身就是一个可部署、可调试、可监控的工作流节点。

关键词 OpenSpec 指的不是某个具体语法,而是一套 可扩展的规范描述协议 ——它允许你用 YAML/JSON 定义结构化语义,但更重要的是,它内置了对“行为契约”的原生支持:比如 on: user.click(button: 'submit') 不是静态文本,而是一个可被事件总线监听、可被模拟器触发、可被日志系统归类的运行时信号; then: [ui.toast('success'), db.update('users', {status: 'active'}), notify.send('in-app')] 也不是待办清单,而是明确声明了执行顺序、失败回滚策略(db 更新失败则 toast 不显示)、以及各动作间的依赖拓扑。而 OPSX (OpenSpec eXecution Engine),就是让这些声明真正活起来的引擎。它不是传统工作流引擎(如 Flowable、Camunda)的轻量版,因为它不处理“任务分配”或“人工审批”,它只做一件事: 将规范中定义的语义行为,精确映射为可插拔的执行单元(Skill)并保障其原子性、可观测性与可组合性

我第一次用 OpenSpec OPSX 实现一个电商优惠券发放流程时,整个过程只写了 87 行 YAML 规范,没有写一行 Java/Python 业务逻辑。我把 coupon.issue 定义为一个 Skill,它内部封装了 Redis 扣减库存、MySQL 写入发放记录、Kafka 推送事件三个动作;然后在主流程里声明 when: order.paid == true and user.level >= 2 then: coupon.issue(amount: 50) 。部署后,OPSX 自动把这个声明编译成一个带熔断、重试、链路追踪的微服务调用链。最让我惊讶的是,当我把 coupon.issue 的 Skill 实现从本地 Redis 切换到分布式锁 + 分库分表的 MySQL 实现时,主流程 YAML 一行没改——因为 OPSX 层屏蔽了实现细节,只认契约接口。这才是 SDD 理想中的样子:规范是稳定的契约,实现是可替换的插件,工作流是契约的自然涌现,而非人为拼凑。

2. 为什么传统工作流引擎在 SDD 场景下集体失效?

很多人看到 “OpenSpec + 工作流” 就立刻联想到 n8n、Dify、Coze 这类低代码平台,甚至去对比 Flowable 的 BPMN 图形化编辑器。这种类比本身就是陷阱。要理解 OPSX 的不可替代性,必须先看清传统方案在 SDD 语境下的结构性缺陷。我用一张真实项目中的对比表说明:

维度 Flowable/Camunda 类引擎 n8n/Dify/Coze 类自动化平台 OpenSpec OPSX
输入本质 流程图(BPMN XML)或 JSON DSL,描述“谁在什么时候做什么” 可视化节点连线,描述“数据从 A 经过 B 变成 C” 语义规范(YAML/JSON) ,描述“当某业务事件发生,系统应如何响应”
执行粒度 任务(Task):人工审批、服务调用、脚本执行,需显式定义每个步骤的输入输出 动作(Action):API 调用、数据库查询、文本处理,强依赖预置连接器 技能(Skill) :可声明式定义的、带契约接口的最小可执行单元(如 payment.process , inventory.reserve
规范与代码关系 流程图是独立资产,业务逻辑仍需写在 Java Service Task 或外部微服务中,二者靠字符串 ID 关联,极易脱节 动作是黑盒,配置参数即全部,无法表达复杂条件分支、状态机、事务边界 规范即契约 :Skill 接口在规范中明确定义(输入 Schema、输出 Schema、错误码、重试策略),实现必须严格遵循,否则启动失败
变更影响范围 改一个审批节点,需修改流程图 + 更新部署包 + 通知所有关联方;改一个服务逻辑,需单独发版 改一个节点配置,可能影响下游所有连线;新增一个 API 调用,需手动填 Token 和 Endpoint 局部变更,全局安全 :只改 inventory.reserve Skill 的实现,主流程无需任何改动;新增一个 loyalty.point.add Skill,只需在规范中声明调用即可
可观测性基础 提供流程实例跟踪,但无法穿透到 Skill 内部逻辑(如 Redis 扣减是否成功、MySQL 是否死锁) 提供节点级日志,但缺乏跨动作的上下文关联(如“第 3 步失败导致第 5 步未执行”) 全链路语义追踪 :从 order.paid 事件开始,到 coupon.issue 的每个子动作(Redis、MySQL、Kafka),Trace ID 携带业务语义标签( event: order.paid , skill: coupon.issue , action: redis.decr

这个表格背后,是三种完全不同的哲学。Flowable 们解决的是“人与系统协同”的流程管理问题,核心是 控制流 ;n8n 们解决的是“数据搬运与简单转换”的自动化问题,核心是 数据流 ;而 OPSX 解决的是“业务意图到系统行为”的精准翻译问题,核心是 语义流 。当你在 Coze 工作流里拖拽一个“发送企业微信消息”节点时,你是在配置一个具体 API;当你在 OpenSpec 规范里写下 notify.send(channel: 'work-wechat', content: '订单已支付') 时,你是在声明一个业务契约——这个契约可以由企业微信 SDK 实现,也可以由钉钉 SDK 实现,甚至可以由一个 Mock 服务实现用于测试,只要它满足 notify.send 的输入输出契约。

我曾在一个金融风控项目中踩过这个坑。初期用 Dify 编排“贷款申请审核”流程,包含 12 个节点:OCR 识别、征信查询、规则引擎打分、人工复核、放款接口调用……上线三个月后,监管要求所有征信查询必须增加“用户二次授权”环节。我们在 Dify 里加了一个新节点,调整了连线,测试通过后上线。结果第二天,风控同事发现部分老用户申请流程卡在“规则引擎打分”后,因为新加入的授权节点返回了空值,而规则引擎的输入校验没做兜底。根本原因在于:Dify 的节点是孤立的,它不理解“征信查询”这个动作在业务语义上必须前置“用户授权”,这个约束无法在流程图里表达,只能靠人脑记忆和代码注释。而换成 OpenSpec 后,我们直接在 credit.query Skill 的契约里声明了 requires: [user.authorization.granted] ,OPSX 在流程编译阶段就报错:“技能 credit.query 依赖 user.authorization.granted,但当前流程未声明该事件”,强制你在规范层面补全业务约束。这不是功能多寡的问题,而是 是否把业务规则作为一等公民嵌入执行引擎 的根本差异。

3. 从零搭建一个可落地的 SDD 工作流:以“用户注册成功后发放新人礼包”为例

光讲理念不够,我们动手做一个真实可用的案例。目标很明确:当用户完成注册( user.registered 事件发生),系统需在 5 秒内完成三件事:1)向用户邮箱发送欢迎邮件;2)在 Redis 中初始化用户积分(100 分);3)向 Kafka 主题 user.activity 发送一条注册事件。这看似简单,但传统做法常陷入“胶水代码地狱”:写一个 Spring Boot Controller 监听注册事件,里面硬编码调用 MailService、RedisTemplate、KafkaTemplate,每个调用都要处理异常、重试、日志。而用 OpenSpec OPSX,我们把它拆解为三个层次:规范定义、Skill 实现、OPSX 部署。

3.1 第一步:用 OpenSpec YAML 定义业务规范( register-flow.yaml

# register-flow.yaml
specVersion: "1.0"
name: "user-registration-bonus"
description: "用户注册成功后,发放欢迎邮件、初始化积分、上报活动事件"

# 声明此流程响应的业务事件
on:
  event: "user.registered"
  # 可选:添加过滤条件,只有邮箱域名为 company.com 的用户才触发
  # filter: "payload.email.endsWith('@company.com')"

# 定义执行步骤:这是一个声明式、无状态的拓扑
steps:
  - id: "send-welcome-email"
    skill: "notify.send"
    input:
      channel: "email"
      to: "${payload.email}"
      subject: "欢迎加入我们的大家庭!"
      body: |
        亲爱的 ${payload.name},
        感谢注册!您的新人礼包(100 积分)已发放,请查收。
        祝您使用愉快!
        —— 产品团队

  - id: "init-user-points"
    skill: "points.init"
    input:
      userId: "${payload.id}"
      amount: 100
      reason: "new_user_bonus"

  - id: "report-activity"
    skill: "analytics.report"
    input:
      topic: "user.activity"
      event: "user_registered"
      payload:
        userId: "${payload.id}"
        timestamp: "${now()}"
        source: "web"

# 定义错误处理策略:任意步骤失败,整体流程标记为 failed,但不回滚(因邮件/积分/上报是最终一致性)
errorHandling:
  strategy: "continue-on-failure" # 或 "abort-on-failure"
  fallbackSteps: []

这段 YAML 的关键点在于:

  • ${payload.email} 模板表达式 ,OPSX 在运行时会从 user.registered 事件的原始负载中提取字段,无需你写 JSONPath 解析代码;
  • skill: "notify.send" 不是指向某个具体 URL,而是一个 技能标识符(Skill ID) ,OPSX 会根据这个 ID 查找已注册的、符合 notify.send 契约的实现;
  • errorHandling 策略是声明式的,你不用写 try-catch,OPSX 引擎自动按此策略执行。

3.2 第二步:实现 notify.send Skill(Java 示例)

Skill 不是黑盒函数,它必须实现 OpenSpec 定义的标准化接口。以 notify.send 为例,其契约(在 notify-skill-contract.yaml 中定义)要求:

# notify-skill-contract.yaml
skillId: "notify.send"
inputSchema:
  type: "object"
  properties:
    channel: { type: "string", enum: ["email", "sms", "work-wechat"] }
    to: { type: "string" }
    subject: { type: "string" }
    body: { type: "string" }
outputSchema:
  type: "object"
  properties:
    sentAt: { type: "string", format: "date-time" }
    messageId: { type: "string" }
errors:
  - code: "INVALID_CHANNEL"
    message: "不支持的通知渠道"
  - code: "SEND_FAILED"
    message: "发送失败,请检查网络或配置"

基于此契约,我们编写一个 Spring Boot 的 Skill 实现:

// NotifySendSkill.java
@Component
public class NotifySendSkill implements Skill<NotifySendInput, NotifySendOutput> {

    @Autowired
    private JavaMailSender mailSender;

    @Override
    public String getSkillId() {
        return "notify.send"; // 必须与契约一致
    }

    @Override
    public NotifySendOutput execute(NotifySendInput input) throws SkillException {
        if (!Arrays.asList("email", "sms", "work-wechat").contains(input.getChannel())) {
            throw new SkillException("INVALID_CHANNEL", "不支持的通知渠道: " + input.getChannel());
        }

        if ("email".equals(input.getChannel())) {
            try {
                MimeMessage message = mailSender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message, true);
                helper.setTo(input.getTo());
                helper.setSubject(input.getSubject());
                helper.setText(input.getBody(), true);
                mailSender.send(message);

                return NotifySendOutput.builder()
                        .sentAt(Instant.now().toString())
                        .messageId(UUID.randomUUID().toString())
                        .build();
            } catch (Exception e) {
                throw new SkillException("SEND_FAILED", "邮件发送失败: " + e.getMessage(), e);
            }
        }

        // 其他渠道(sms, work-wechat)的实现省略...
        throw new UnsupportedOperationException("渠道 " + input.getChannel() + " 暂未实现");
    }
}

注意:这个类上标注了 @Component ,意味着它会被 Spring 容器管理;OPSX 启动时会自动扫描所有 Skill 实现类,并将其注册到内部技能仓库。你不需要在 YAML 里写任何 URL 或 Class 名,OPSX 通过 getSkillId() 方法自动绑定。

3.3 第三步:OPSX 引擎部署与事件驱动

部署 OPSX 很简单:它本身就是一个 Spring Boot 应用。你只需要:

  1. register-flow.yaml 放在 src/main/resources/flows/ 目录下;
  2. NotifySendSkill PointsInitSkill AnalyticsReportSkill 三个实现类打包进应用;
  3. 启动应用,OPSX 会自动加载所有 Flow 和 Skill。

最关键的一步是 触发事件 。OPSX 提供了标准的 HTTP API 来发布事件:

curl -X POST http://localhost:8080/v1/events \
  -H "Content-Type: application/json" \
  -d '{
    "event": "user.registered",
    "payload": {
      "id": "usr_abc123",
      "name": "张三",
      "email": "zhangsan@example.com"
    }
  }'

OPSX 收到后,会:

  • 匹配到 register-flow.yaml (因为 on.event == "user.registered" );
  • 创建一个流程实例(Instance),分配唯一 ID;
  • steps 顺序,依次调用 notify.send points.init analytics.report 三个 Skill;
  • 每个 Skill 的调用都包裹在统一的监控、日志、错误处理框架内;
  • 最终,你可以在 OPSX 的 Web 控制台( http://localhost:8080/ui )看到这个实例的完整执行轨迹,包括每个 Skill 的输入、输出、耗时、错误堆栈。

这个过程没有一行“胶水代码”,没有手动编排,没有硬编码的 URL。你写的 YAML 是业务人员能看懂的规范,你写的 Java 类是工程师能维护的 Skill,OPSX 是那个沉默的翻译官,确保二者严丝合缝。

4. OPSX 的“超能力”:Superpowers 如何让 SDD 从可行走向高效

OpenSpec 社区常提的 “Superpowers” 并非营销噱头,而是 OPSX 引擎内置的几项关键能力,它们共同解决了 SDD 落地中最顽固的“最后一公里”问题: 如何让规范不只是能跑,还要跑得聪明、安全、可进化 。这些能力不是可选插件,而是引擎的核心组成部分,一旦启用,整个工作流的行为模式就会质变。

4.1 Superpower 1:契约驱动的自动 Stub 与 Mock( superpower: mock

在开发早期, notify.send 的邮件服务可能还没对接好,或者 analytics.report 的 Kafka 集群在测试环境不可用。传统做法是写一堆 if (env == 'test') 的条件分支,或者用 Mockito 手动 mock,既污染业务代码,又难以保证 mock 行为与真实契约一致。OPSX 的 mock Superpower 让你彻底告别这个烦恼。

只需在 application.yml 中开启:

openspec:
  superpowers:
    mock:
      enabled: true
      # 为特定 Skill 指定 mock 行为
      skills:
        - id: "notify.send"
          response: # 固定返回
            sentAt: "2024-01-01T00:00:00Z"
            messageId: "mock-12345"
        - id: "analytics.report"
          delay: 100 # 模拟网络延迟 100ms
          errorRate: 0.1 # 10% 概率抛出 SEND_FAILED 错误

启动后,OPSX 会自动拦截所有对 notify.send analytics.report 的调用,按配置返回模拟响应或注入故障。关键是,这个 mock 完全基于 Skill 的契约定义 :它只返回 outputSchema 中声明的字段,如果契约里没定义 messageId ,mock 就不会返回;它抛出的错误码也严格限定在 errors 列表中。这意味着,你的前端、测试脚本、甚至产品经理的流程演示,都可以在 0 依赖真实服务的情况下,100% 真实地运行整个工作流。我团队在一次大促前压测中,就用这个功能快速构建了“高并发注册”场景:Mock 掉所有外部依赖,只保留 Redis 积分扣减的真实逻辑,瞬间将压测环境搭建时间从 3 天缩短到 2 小时。

4.2 Superpower 2:基于规范的自动契约测试( superpower: test

SDD 最怕什么?规范写了,代码也写了,但没人敢保证代码真的实现了规范。OPSX 的 test Superpower 把这个问题变成了一个 mvn test 命令。它能自动解析你的 YAML 规范,生成对应的 JUnit 测试用例。

例如,对于 register-flow.yaml ,它会自动生成:

@Test
void testRegisterFlow_EmailSentOnSuccess() throws Exception {
    // 给定:一个注册事件
    UserRegisteredEvent event = new UserRegisteredEvent("usr_001", "李四", "lisi@test.com");

    // 当:流程执行
    FlowResult result = flowExecutor.execute("user-registration-bonus", event);

    // 那么:邮件 Skill 应被调用,且输入正确
    verify(notifySendSkill).execute(argThat(input -> 
        "email".equals(input.getChannel()) && 
        "lisi@test.com".equals(input.getTo()) &&
        input.getSubject().contains("欢迎")
    ));
}

更厉害的是,它还能生成 边界测试 :比如,当 payload.email 为空时,流程是否按 errorHandling 策略正确处理?当 notify.send 抛出 SEND_FAILED 时, points.init 是否依然被执行?这些测试用例不是手写的,而是由 OPSX 根据规范的 filter inputSchema errorHandling 等元信息 推导生成 的。每次你修改 YAML,重新运行 mvn test ,就能立刻知道改动是否破坏了契约。这不再是“测试覆盖率”,而是“规范覆盖率”。

4.3 Superpower 3:运行时语义监控与智能告警( superpower: observe

传统监控看的是 HTTP 500 错误率 JVM GC 时间 ,OPSX 的 observe Superpower 看的是 business.error.rate (业务错误率)。它把监控指标直接锚定在规范语义上。

在 OPSX 控制台,你可以看到:

  • user-registration-bonus 流程的 成功率 (按 errorHandling.strategy 计算);
  • notify.send Skill 的 渠道分布 (email/sms/work-wechat 各占多少);
  • points.init 平均耗时 ,并按 reason 字段( new_user_bonus / referral_bonus )自动分组;
  • analytics.report topic: "user.activity" 出现连续 5 次 SEND_FAILED ,自动触发告警,并附带最近 10 次失败的 payload.userId 列表,方便运营快速定位是某个用户群体的问题。

这一切都不需要你写 Prometheus Exporter 或 Grafana Dashboard。OPSX 在执行每个 Skill 时,自动注入 OpenTelemetry Span,并将 event skillId input 中的关键业务字段(如 userId , reason )作为 Span Attributes 上报。监控系统拿到的,不再是冰冷的 http.server.request.duration ,而是有血有肉的 user.registration.bonus.success

有一次,我们发现 user-registration-bonus 的成功率从 99.9% 突然跌到 95%,告警里显示 notify.send INVALID_CHANNEL 错误激增。点开详情,发现所有失败请求的 channel 字段都是 wechat (小写),而契约里定义的枚举是 ["email", "sms", "work-wechat"] 。根源很快定位:前端 SDK 升级后,把 work-wechat 错拼成了 wechat 。如果没有 observe Superpower 的语义级监控,这个问题可能要等用户投诉才能发现。

5. 从单点突破到组织级演进:SDD 工作流的规模化实践路径

把 OPSX 用在一个注册流程上,是技术验证;把它变成整个研发团队的默认工作方式,才是真正的价值释放。我们花了 6 个月,在一个 50 人的产研团队中完成了这个演进,总结出三条必须踩实的路径,每一步都对应一个真实的组织阵痛。

5.1 路径一:建立“规范即代码”的版本治理(GitOps for Spec)

最初,大家把 YAML 文件随手丢在个人电脑或共享网盘里,很快出现“哪个是最新版?”、“这个流程为什么线上没生效?”的混乱。我们强制推行 OpenSpec GitOps

  • 所有 *.yaml 规范文件必须存放在 gitlab.com/org/openspec-specs 仓库的 main 分支;
  • 每个规范文件名必须包含领域前缀,如 auth/user-registration-bonus.yaml payment/order-paid-handler.yaml
  • 修改规范必须走 Merge Request(MR),MR 描述里必须填写 #JIRA-123 关联需求;
  • OPSX 引擎配置为 watch Git 仓库 ,一旦 main 分支有推送,自动拉取、校验(语法 + 契约)、热加载新规范,无需重启。

这个看似简单的流程,带来了质变:

  • 可追溯 git blame 能立刻看到是谁、何时、为什么修改了 points.init errorHandling 策略;
  • 可审计 :安全团队可以定期扫描 main 分支,检查是否有 skill: "db.raw-sql" 这类高危 Skill 被引入;
  • 可协作 :产品经理可以直接在 MR 评论里说:“这里 body 模板的措辞请改成‘您的专属礼包’,谢谢”,工程师直接在评论里修改并推送。

提示:我们用了一个小技巧规避“配置漂移”——在 OPSX 启动时,它会计算当前加载的所有规范文件的 SHA256,并写入一个 spec-checksum.json 文件。运维同学每次发布前,只需比对这个 checksum 与 Git 仓库的 commit ID 是否一致,就能 100% 确认线上运行的规范就是代码库里的最新版。

5.2 路径二:构建组织级 Skill 共享仓库(Internal Skill Registry)

随着项目增多,“重复造轮子”成为新瓶颈。A 团队写了 notify.send ,B 团队又写了一个几乎一样的 email.sender ;C 团队的 payment.refund 和 D 团队的 order.cancel-refund 逻辑高度重合。我们建立了 Internal Skill Registry

  • 所有通用 Skill(如 notify.send , db.upsert , cache.get )必须发布到公司 Nexus 私服,Group ID 为 com.company.openspec.skill
  • 每个 Skill 发布时,必须附带完整的 *-contract.yaml 契约文件;
  • 新项目在 pom.xml 中声明依赖 <groupId>com.company.openspec.skill</groupId><artifactId>notify-skill</artifactId> ,OPSX 启动时自动扫描并注册。

这带来两个直接收益:

  • 质量提升 notify-skill 由专门的“通知中台”团队维护,他们为 work-wechat 渠道增加了企业微信会话存档合规检查,所有使用它的项目自动获得这项能力;
  • 成本下降 :一个新项目接入邮件通知,从原来平均 2 人日(调研、开发、测试),缩短到 0.5 人日(引入依赖 + 配置参数)。

注意:Skill 的版本管理极其重要。我们约定 major.minor.patch 版本号规则: patch (如 1.0.1)只修复 bug,向后兼容; minor (如 1.1.0)可新增可选字段,不破坏现有契约; major (如 2.0.0)表示契约不兼容,必须在 MR 中强制要求所有引用方升级。OPSX 在加载时会校验契约版本,若发现 flow.yaml 声明依赖 notify.send@1.x ,而实际加载的是 2.0.0 ,则启动失败并报错。

5.3 路径三:将 SDD 工作流嵌入研发全生命周期(CI/CD Integration)

最后一步,是让 SDD 成为研发流水线的“第一道门”。我们在 Jenkins/GitLab CI 中加入了两个关键检查:

  • 规范校验阶段 mvn openspec:validate ,检查 YAML 语法、契约引用有效性(如 skill: "xxx" 是否在 Registry 中存在)、 filter 表达式是否可编译;
  • 契约测试阶段 mvn test -Dtest=SpecContractTest ,运行由 test Superpower 生成的、覆盖所有规范分支的测试用例。

这意味着,任何一次代码提交,如果它修改的 YAML 规范存在语法错误,或者新增的 Skill 实现没有满足契约(比如少返回了一个 messageId 字段),CI 就会立即失败,开发者必须修复后才能合并。SDD 不再是“上线前补的文档”,而是和单元测试一样,是代码入库的强制门槛。

这个改变带来的文化转变是深远的。以前,产品经理提需求,工程师评估工时,双方争论“这个需求要写多少行代码”;现在,产品经理提需求,工程师第一反应是:“这个业务规则,能不能用 OpenSpec 规范清晰地表达出来?如果不能,说明需求本身就有歧义。” 规范,真正成为了沟通的通用语言。

6. 我的实战体会:SDD 不是银弹,但它是让复杂系统保持呼吸的肺

写到这里,我想分享一个深夜的顿悟时刻。那是我们上线 OPSX 后第三个月,一个紧急需求:因政策变化,所有新注册用户必须在 24 小时内完成实名认证,否则冻结账户。法务给了明确的判定逻辑,产品画了流程图,开发评估要 5 人日。

我打开 auth/user-registration-bonus.yaml ,复制粘贴,改名为 auth/user-identity-enforcement.yaml ,然后只做了三件事:

  1. on.event user.registered 改成 user.identity.verified
  2. steps 末尾加了一行: - id: "freeze-if-expired" skill: "account.freeze" input: { userId: "${payload.userId}", reason: "identity_expired" }
  3. errorHandling 下加了一条 timeout: "PT24H" (24 小时超时)。

保存,提交 MR,CI 通过,上线。全程 18 分钟。

那一刻我没有感到兴奋,只有一种平静的确认: SDD 的终极价值,不是让你写更少的代码,而是让你把最宝贵的精力,从“如何让机器执行”转移到“如何让人类达成共识”上 。OPSX 解决了前者,而后者,永远需要产品经理、工程师、法务、运营围坐在一起,逐字推敲那句 when: user.identity.verified == false and now() > registeredAt.plusHours(24) 是否准确表达了政策本意。

所以,如果你正被“需求反复变更”、“上下游对齐成本高”、“上线后问题定位难”所困扰,不妨从一个最小的、高价值的业务流程开始,用 OpenSpec 写下第一份真正可执行的规范。不要追求完美,先让它跑起来。当你的第一个 user.registered 事件触发了 notify.send points.init analytics.report 三个 Skill,并在控制台看到那条绿色的 SUCCESS 日志时,你就已经踏上了那条让工作流不再死板、让规范真正驱动开发的道路。

这条路没有终点,但每一步,都让系统离“可理解、可预测、可进化”更近一点。而这,正是我们作为工程师,所能交付的最坚实的价值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值