M5(2/3): process 用例与流转 —— 流程引擎的确定性调度
- routing domain:选边(XOR 恰取一条 + 默认分支兜底;AND 全走)、边映射装配(四类来源 + S-FEEL 转换)、AND 汇合回齐(容忍分支不阻汇合)、审批点驳回走向声明式 - process-service:起单 → 调度节点 → 负责人四策略解析(结果与依据留痕)→ 活动起单 / 审批点卡工位 / 终点收束按来源回执;任务终态到达继续流转或走失败走向四选一; 审批驳回按声明回指定节点重开新实例;状态每次变动后重算聚合投影 - adapter:流程包(id × version)、工作流实例、节点实例三表持久 —— 崩溃后可续跑 ADR 待补项登记为 debt M5-1:§6.1 的 Mastra workflow 编译器作为可替换 adapter 后补, 当前由自持确定性状态机承担,语义等价、usecase 不动 325 个测试通过,门禁五道全绿 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
co-authored by
Claude Opus 5
parent
291fc39179
commit
a8f6eef610
+120
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* module: process —— 本模块要外界提供的能力(编码规范 §10.1 / §5.3)。
|
||||
*/
|
||||
import type { ProcessPackage, StaffId, TerminalState, WorkflowState } from '@contracts';
|
||||
import type { NodeInstance } from './internal/domain/owner-resolution.ts';
|
||||
import type { ActivityContractFace } from './internal/domain/closure.ts';
|
||||
export type Clock = {
|
||||
now(): Date;
|
||||
};
|
||||
export type IdGenerator = {
|
||||
next(): string;
|
||||
};
|
||||
/** 工作流实例的持久面 —— 崩溃后可续跑 */
|
||||
export type WorkflowRecord = {
|
||||
readonly id: string;
|
||||
readonly packageId: string;
|
||||
readonly packageVersion: number;
|
||||
readonly subject: string;
|
||||
readonly state: WorkflowState;
|
||||
/** 来源:凡单必有来源(触发器 / 登记人 / 上游系统) */
|
||||
readonly source: {
|
||||
kind: 'periodic' | 'event' | 'registration';
|
||||
ref: string;
|
||||
by?: string;
|
||||
};
|
||||
readonly initiation: Record<string, unknown>;
|
||||
/** 各节点输出口载荷 —— 边映射装配的来源 */
|
||||
readonly ports: Record<string, Record<string, unknown>>;
|
||||
readonly vars: Record<string, unknown>;
|
||||
readonly startedAt: string;
|
||||
readonly finishedAt?: string;
|
||||
};
|
||||
export type ProcessStore = {
|
||||
savePackage(pkg: ProcessPackage): Promise<void>;
|
||||
getPackage(id: string, version?: number): Promise<ProcessPackage | undefined>;
|
||||
listPackages(): Promise<ProcessPackage[]>;
|
||||
publishPackage(id: string, version: number): Promise<void>;
|
||||
insertWorkflow(record: WorkflowRecord): Promise<void>;
|
||||
getWorkflow(id: string): Promise<WorkflowRecord | undefined>;
|
||||
listWorkflows(limit: number): Promise<WorkflowRecord[]>;
|
||||
updateWorkflow(id: string, patch: Partial<WorkflowRecord>): Promise<WorkflowRecord>;
|
||||
listInstances(workflowId: string): Promise<NodeInstance[]>;
|
||||
insertInstance(workflowId: string, instance: NodeInstance & {
|
||||
taskId?: string;
|
||||
approvalId?: string;
|
||||
}): Promise<void>;
|
||||
updateInstance(workflowId: string, nodeId: string, instance: number, patch: Partial<NodeInstance> & {
|
||||
taskId?: string;
|
||||
}): Promise<void>;
|
||||
findInstanceByTask(taskId: string): Promise<{
|
||||
workflowId: string;
|
||||
nodeId: string;
|
||||
instance: number;
|
||||
} | undefined>;
|
||||
};
|
||||
/** 活动契约面 —— app 注入 `activity-registry`(L4):编排校验与起单都要它 */
|
||||
export type ActivityDirectory = {
|
||||
faces(): Promise<Map<string, ActivityContractFace>>;
|
||||
};
|
||||
/** 岗位与在岗人员 —— app 注入 `org`(L1):负责人四策略解析的候选集 */
|
||||
export type OrgDirectory = {
|
||||
positions(): Promise<Set<string>>;
|
||||
candidates(position: string): Promise<Array<{
|
||||
staffId: string;
|
||||
name: string;
|
||||
openTasks: number;
|
||||
}>>;
|
||||
};
|
||||
/** 起单与终态 —— app 注入 `task`(L6) */
|
||||
export type TaskGateway = {
|
||||
start(input: {
|
||||
activityId: string;
|
||||
ownerId: StaffId;
|
||||
title: string;
|
||||
workflowId: string;
|
||||
nodeId: string;
|
||||
data: Record<string, unknown>;
|
||||
message?: string;
|
||||
}): Promise<{
|
||||
id: string;
|
||||
}>;
|
||||
};
|
||||
/** 审批点 —— app 注入 `human-tool`(L3):审批单卡到审批人工位 */
|
||||
export type ApprovalGateway = {
|
||||
raise(input: {
|
||||
workflowId: string;
|
||||
nodeId: string;
|
||||
approverId: StaffId;
|
||||
subject: string;
|
||||
basis: ReadonlyArray<{
|
||||
k: string;
|
||||
v: string;
|
||||
}>;
|
||||
}): Promise<{
|
||||
id: string;
|
||||
}>;
|
||||
};
|
||||
/** S-FEEL —— app 注入 `@sfeel`:流转零 LLM */
|
||||
export type Sfeel = {
|
||||
condition(expression: string, scope: Readonly<Record<string, unknown>>): boolean;
|
||||
expression(expression: string, scope: Readonly<Record<string, unknown>>): unknown;
|
||||
};
|
||||
/** 流转记入事件 —— app 注入 `event`(L1) */
|
||||
export type FlowEventPublisher = {
|
||||
publish(input: {
|
||||
workflowId: string;
|
||||
kind: string;
|
||||
detail: Record<string, unknown>;
|
||||
}): Promise<void>;
|
||||
};
|
||||
/** 终态回执 —— 登记人收消息 */
|
||||
export type ReceiptNotifier = {
|
||||
notify(input: {
|
||||
to: StaffId;
|
||||
workflowId: string;
|
||||
subject: string;
|
||||
state: WorkflowState;
|
||||
}): Promise<void>;
|
||||
};
|
||||
export type { TerminalState };
|
||||
Reference in New Issue
Block a user