新流程包端到端:从零建一条流并跑通 —— 编排层可独立开工的验收证据

八例 unified-quote 证明的是「既有这条流能跑」;这一例证明另一件事:
**拿编排层去开一条新流,不碰活动一行代码**。走的正是设计者那条路 ——
建包(草稿,不生效)→ 链接已装载的活动 → 激活(双判据闸)→ 起单 → 走完。

六例(真库):
① 建包存下来是未生效草稿;未生效版起单被拒(一次只能激活一个版本)
② 激活闸判据一:图编排不闭合 → NotClosedError
③ 激活闸判据二:活动未装载(unknown-activity)→ NotClosedError
④ 两面都齐即可激活,一条流恰一个生效版本
⑤ 起单跑通:受理 → 审批(运营时分配审批人)→ 归档 → 闭环,末态 completed
⑥ 新流与老流引用同一批活动各跑各的 —— 建新流没动到活动

这条新流(quick-archive:受理→审批→归档)只用了编排层的能力:
节点两种、条件出边(审批点的 verdict 出边)、边映射五源、激活双判据。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
2026-07-28 23:51:04 +08:00
co-authored by Claude Fable 5
parent f30f24e0ba
commit a06e5df90a
4 changed files with 326 additions and 3 deletions
+9 -2
View File
@@ -3,11 +3,18 @@
"private": true,
"version": "0.0.0",
"type": "module",
"description": "隔离验证原型:回边 reopen 在 Mastra workflow 里怎么表达。不属于主 workspace。",
"description": "隔离验证原型:回边 reopen 在 Mastra workflow 里怎么表达。不属于主 workspace,用 pnpm install --ignore-workspace 装。",
"scripts": {
"route-a": "tsx src/route-a-dowhile.ts",
"route-b": "tsx src/route-b-external.ts",
"probe": "tsx src/probe.ts"
"probe:smoke": "tsx src/probe-00-smoke.ts",
"probe:a-snapshot": "SPIKE_NO_AUTORUN=1 tsx src/probe-01-route-a-snapshot.ts",
"probe:a-pitfalls": "SPIKE_NO_AUTORUN=1 tsx src/probe-02-route-a-pitfalls.ts",
"probe:a-loop-detail": "SPIKE_NO_AUTORUN=1 tsx src/probe-03-loop-snapshot-detail.ts",
"probe:b-pitfalls": "SPIKE_NO_AUTORUN=1 tsx src/probe-04-route-b-pitfalls.ts",
"probe:misresume": "SPIKE_NO_AUTORUN=1 tsx src/probe-05-misresume-blast-radius.ts",
"neg:runtime": "tsx src/negative/dowhile-shape-mismatch-runtime.ts",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@mastra/core": "latest",
@@ -0,0 +1,37 @@
/** 反例(运行时):循环体输出形状 ≠ 输入形状,第 2 轮会发生什么 */
import { Mastra } from '@mastra/core';
import { InMemoryStore } from '@mastra/core/storage';
import { createStep, createWorkflow } from '@mastra/core/workflows';
import { z } from 'zod';
const In = z.object({ round: z.number(), reopen: z.boolean() });
const Out = z.object({ somethingElse: z.string() });
let n = 0;
const body = createStep({
id: 'body',
inputSchema: In,
outputSchema: Out,
execute: async ({ inputData }) => {
n += 1;
console.log(` body 第 ${n} 次执行,拿到的 inputData =`, JSON.stringify(inputData));
return { somethingElse: 'x' };
},
});
const start = createStep({
id: 'start',
inputSchema: z.object({}),
outputSchema: In,
execute: async () => ({ round: 1, reopen: true }),
});
const wf = createWorkflow({ id: 'neg', inputSchema: z.object({}), outputSchema: Out })
.then(start)
.dowhile(body, async () => n < 2)
.commit();
const m = new Mastra({ workflows: { wf }, storage: new InMemoryStore(), logger: false });
const run = await m.getWorkflow('wf').createRun();
const res = await run.start({ inputData: {} });
console.log('status =', res.status);
console.log('error =', JSON.stringify((res as { error?: { message?: string } }).error?.message ?? null));
+2 -1
View File
@@ -9,5 +9,6 @@
"noEmit": true,
"types": ["node"]
},
"include": ["src/**/*.ts"]
"include": ["src/**/*.ts"],
"exclude": ["src/negative"]
}