forked from ChaiHao/BPOS-MVP
范式退役:活动只剩一种、只跑 Loop;审批活动可管;活动库重做
用户定的两件,一并落地。
**一、活动不再分 flow 和 loop —— 彻底退役 flow**
· `flow-engine` 模块整个删除(runner 379 行 + step-sequence 184 行 + 测试);
· `paradigm` 从清单身份、`activity_package`/`task` 两张表、任务卡与活动库一并退场;
`businessModel` 不再是判别联合 —— 只有案例模型(CMMN + 说明书 + DMN)一形;
· task 的引擎分派从「按 paradigm 取两个之一」收成**唯一的引擎**;
· `activities/` 四个 flow 活动(A1 受理 / A4 定价 / A6 议价 / A7 归档)各写了一份
案例模型:阶段照原来的步分,触达世界的项一律 manualActivationRule,
能算的交 DMN(A1 的三分类 P-03、A4 的 P-01/P-02)不交 Agent;
· 六个占位槽位的骨架从「机器步落台账 + 一张验收单」改成案例骨架,包版本 0.8.0 → 0.9.0。
**代价写在明处,不假装没有**:`turn-runner` 每一拍都要 `agent.decide` ——
环境里没有模型 key,案例活动一步也走不动。三套端到端(统一报价 / 新建流程包 / 测试台
Trace)整套跳过,文件头写明恢复条件:①有可用模型 ②走法改写成按 Enabled 集推进。
**不许把断言改松让它变绿** —— 绿得不诚实比红着更坏。debt.md 已记。
**二、审批活动可管**(新能力)
· `sys.approval_template`:审批点**可复用的那一半** —— 审批人看哪几项、按什么名字看、
怎么催、说什么话。谁来审不在里面(与活动点同口径,运营时轮值);驳回回哪个节点
也不在里面(那是每张图自己的事,留在节点上);
· 三条路由 + 引用反查:还被审批点引着就不许删(409),删了那些节点会**静默**退回旧行为;
· 运行时 `basisOf`:引了模板就按模板筛与改名,没引即旧行为(载荷全摊开)。
模板改了只影响新发出的审批单 —— 在途单的依据在发出那一刻已定形。
**三、活动库重做**:一区两格 —— 「活动(装进来的)」与「审批活动(配出来的)」,
都用流程卡那套两段式卡片(头 + 四格数据板),幽灵卡当入口(装入活动 / 新建审批活动);
「标准/案例」那一维随范式一起撤,业务分类成了唯一的一维,以行内小签呈现。
迁移 0020:两张表 drop paradigm、建 approval_template。已在开发库跑过并重播种。
实测(丁子乔账号):建「定价审批」模板 → 流程包 A5 属性里选得到 → 引用反查计数正确。
四闸绿(api:check 随本提交)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -53,7 +53,6 @@ function harness(): Harness {
|
||||
},
|
||||
activities: {
|
||||
load: async () => ({
|
||||
paradigm: 'flow' as const,
|
||||
caps: { steps: 40, tokens: 200000, humanCalls: 2, activeMinutes: 60 },
|
||||
envelope: {},
|
||||
inputSchema: INPUT_SCHEMA,
|
||||
@@ -62,10 +61,7 @@ function harness(): Harness {
|
||||
}),
|
||||
},
|
||||
schemas: { validate: () => ({ ok: true, errors: [] }) },
|
||||
engines: {
|
||||
flow: { load: async () => undefined, advance: async () => ({ status: 'running' }), onEvent: async () => ({ status: 'running' }) },
|
||||
loop: { load: async () => undefined, advance: async () => ({ status: 'running' }), onEvent: async () => ({ status: 'running' }) },
|
||||
},
|
||||
engine: { load: async () => undefined, advance: async () => ({ status: 'running' }), onEvent: async () => ({ status: 'running' }) },
|
||||
memory: { append: async () => undefined, hasHistory: async () => true, seal: async () => undefined, distill: async () => undefined },
|
||||
landing: {
|
||||
land: async () => ({ converged: true, emittedPorts: [] as string[], ledgerRowsMerged: 0, facts: {} as LandedFacts }),
|
||||
|
||||
@@ -33,7 +33,6 @@ function harness(land: () => Promise<never> | Promise<{ converged: boolean; emit
|
||||
h.task = {
|
||||
id: TASK,
|
||||
activityId: 'a-1',
|
||||
paradigm: 'flow',
|
||||
ownerId: 's-1' as Task['ownerId'],
|
||||
title: '占位活动',
|
||||
runtime: 'running',
|
||||
@@ -59,7 +58,6 @@ function harness(land: () => Promise<never> | Promise<{ converged: boolean; emit
|
||||
},
|
||||
activities: {
|
||||
load: async () => ({
|
||||
paradigm: 'flow' as const,
|
||||
caps: h.task.caps,
|
||||
envelope: {},
|
||||
inputSchema: {},
|
||||
@@ -68,10 +66,11 @@ function harness(land: () => Promise<never> | Promise<{ converged: boolean; emit
|
||||
}),
|
||||
},
|
||||
schemas: { validate: () => ({ ok: true, errors: [] }) },
|
||||
engines: {
|
||||
// 谱走完 + 放行通过 —— 接下来就该落地
|
||||
flow: { load: async () => undefined, advance: async () => ({ status: 'finished', released: true, selectedPorts: {} }), onEvent: async () => ({ status: 'running' }) },
|
||||
loop: { load: async () => undefined, advance: async () => ({ status: 'running' }), onEvent: async () => ({ status: 'running' }) },
|
||||
// 案子办完 + 放行通过 —— 接下来就该落地
|
||||
engine: {
|
||||
load: async () => undefined,
|
||||
advance: async () => ({ status: 'finished', released: true, selectedPorts: {} }),
|
||||
onEvent: async () => ({ status: 'running' }),
|
||||
},
|
||||
memory: {
|
||||
append: async (input) => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* 任务运行时:生命周期与**终态五名裁定**、Harness 预算执行器 / 停滞熔断、
|
||||
* 控制三语义、改派、断点续跑。范式(loop / flow)在此汇流 —— 对流程层与交互层不可区分。
|
||||
*/
|
||||
import type { BudgetCaps, ControlSemantic, Paradigm, StaffId, TaskId, TaskRuntimeState, TerminalState } from '@contracts';
|
||||
import type { BudgetCaps, ControlSemantic, StaffId, TaskId, TaskRuntimeState, TerminalState } from '@contracts';
|
||||
import type { BudgetBreach, Consumption, HarnessVerdict } from './internal/domain/harness.ts';
|
||||
import type { ControlOutcome, ResumeReadiness, TaskSnapshot, TerminalCause } from './internal/domain/lifecycle.ts';
|
||||
|
||||
@@ -15,7 +15,6 @@ export type {
|
||||
ControlOutcome,
|
||||
ControlSemantic,
|
||||
HarnessVerdict,
|
||||
Paradigm,
|
||||
ResumeReadiness,
|
||||
TaskRuntimeState,
|
||||
TaskSnapshot,
|
||||
@@ -50,7 +49,6 @@ export type LandedFacts = {
|
||||
export type Task = {
|
||||
readonly id: TaskId;
|
||||
readonly activityId: string;
|
||||
readonly paradigm: Paradigm;
|
||||
/** 起单来源:工作流节点;登记触发的直起单为 undefined */
|
||||
readonly workflowId?: string;
|
||||
readonly nodeId?: string;
|
||||
|
||||
@@ -9,7 +9,6 @@ export type {
|
||||
ControlOutcome,
|
||||
ControlSemantic,
|
||||
HarnessVerdict,
|
||||
Paradigm,
|
||||
ResumeReadiness,
|
||||
StartTaskInput,
|
||||
Task,
|
||||
|
||||
@@ -9,7 +9,6 @@ export const taskTable = sys.table(
|
||||
{
|
||||
id: text('id').primaryKey(),
|
||||
activityId: text('activity_id').notNull(),
|
||||
paradigm: text('paradigm').notNull(),
|
||||
workflowId: text('workflow_id'),
|
||||
nodeId: text('node_id'),
|
||||
/** 恰有一名负责人 */
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* task 存储 adapter —— Drizzle 只准出现在 adapter(编码规范 §5.3)。
|
||||
*/
|
||||
import { and, asc, eq, isNull, sql } from 'drizzle-orm';
|
||||
import type { BudgetCaps, Paradigm, StaffId, TaskId, TaskRuntimeState, TerminalState } from '@contracts';
|
||||
import type { BudgetCaps, StaffId, TaskId, TaskRuntimeState, TerminalState } from '@contracts';
|
||||
import type { Db } from '@shared/db.ts';
|
||||
import type { TaskStore } from '../../port.ts';
|
||||
import type { Task } from '../../contract.ts';
|
||||
@@ -15,7 +15,6 @@ function toTask(row: Row): Task {
|
||||
return {
|
||||
id: row.id as TaskId,
|
||||
activityId: row.activityId,
|
||||
paradigm: row.paradigm as Paradigm,
|
||||
...(row.workflowId === null ? {} : { workflowId: row.workflowId }),
|
||||
...(row.nodeId === null ? {} : { nodeId: row.nodeId }),
|
||||
ownerId: row.ownerId as StaffId,
|
||||
@@ -43,7 +42,6 @@ export function createTaskStore(db: Db): TaskStore {
|
||||
await db.insert(taskTable).values({
|
||||
id: task.id,
|
||||
activityId: task.activityId,
|
||||
paradigm: task.paradigm,
|
||||
workflowId: task.workflowId ?? null,
|
||||
nodeId: task.nodeId ?? null,
|
||||
ownerId: task.ownerId,
|
||||
|
||||
@@ -30,8 +30,8 @@ export type TaskServiceDeps = {
|
||||
readonly store: TaskStore;
|
||||
readonly activities: ActivityLoader;
|
||||
readonly schemas: SchemaValidator;
|
||||
/** 范式引擎按 paradigm 分派 —— 对上层不可区分 */
|
||||
readonly engines: Readonly<Record<'loop' | 'flow', ParadigmEngine>>;
|
||||
/** 唯一的引擎(2026-07-29:活动不再分范式,内部实现都是 Loop) */
|
||||
readonly engine: ParadigmEngine;
|
||||
readonly memory: MemoryRecorder;
|
||||
/** 落地收敛 —— 放行通过的那一刻才碰事实 */
|
||||
readonly landing: LandingGateway;
|
||||
@@ -72,10 +72,6 @@ export function createTaskService(deps: TaskServiceDeps): TaskService {
|
||||
return task;
|
||||
}
|
||||
|
||||
function engineOf(task: Task): ParadigmEngine {
|
||||
return deps.engines[task.paradigm];
|
||||
}
|
||||
|
||||
/** Harness 在环外先判:越限即熔断并挂起,处置归治理台 */
|
||||
async function harnessCheck(task: Task, stallAfter: string) {
|
||||
const lastProgress = (await deps.store.lastProgressAt(task.id)) ?? new Date(task.startedAt);
|
||||
@@ -103,7 +99,6 @@ export function createTaskService(deps: TaskServiceDeps): TaskService {
|
||||
const task: Task = {
|
||||
id: taskIdSchema.parse(deps.ids.next()),
|
||||
activityId: input.activityId,
|
||||
paradigm: loaded.paradigm,
|
||||
...(input.workflowId === undefined ? {} : { workflowId: input.workflowId }),
|
||||
...(input.nodeId === undefined ? {} : { nodeId: input.nodeId }),
|
||||
ownerId: input.ownerId,
|
||||
@@ -123,7 +118,7 @@ export function createTaskService(deps: TaskServiceDeps): TaskService {
|
||||
// message 计入初始观察、全程留痕;**不得扩大授权边界**
|
||||
detail: { data: input.data, message: input.message, envelope: loaded.envelope },
|
||||
});
|
||||
await engineOf(task).load(task.id, loaded.businessModel);
|
||||
await deps.engine.load(task.id, loaded.businessModel);
|
||||
await deps.interaction.setPhase(task.id, 'active');
|
||||
if (missing.length > 0) {
|
||||
await deps.memory.append({
|
||||
@@ -169,7 +164,7 @@ export function createTaskService(deps: TaskServiceDeps): TaskService {
|
||||
}
|
||||
|
||||
const startedAt = deps.clock.now().getTime();
|
||||
const outcome = await engineOf(task).advance(taskId);
|
||||
const outcome = await deps.engine.advance(taskId);
|
||||
// 步计量:loop 的一次决策循环 / flow 的一个声明步。
|
||||
// 活跃时长按**这一拍真正花掉的时间**计 —— 挂起等人的时间不算活跃,那是世界等待。
|
||||
const used = await deps.store.addConsumption(taskId, {
|
||||
@@ -303,7 +298,7 @@ export function createTaskService(deps: TaskServiceDeps): TaskService {
|
||||
}
|
||||
}
|
||||
|
||||
await engineOf(task).onEvent(taskId, event);
|
||||
await deps.engine.onEvent(taskId, event);
|
||||
await deps.store.markProgress(taskId, deps.clock.now());
|
||||
return this.tick(taskId);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* module: task —— 本模块要外界提供的能力(编码规范 §10.1 / §5.3)。
|
||||
*/
|
||||
import type { BudgetCaps, Paradigm, StaffId, TaskId, TerminalState } from '@contracts';
|
||||
import type { BudgetCaps, StaffId, TaskId, TerminalState } from '@contracts';
|
||||
import type { Consumption } from './internal/domain/harness.ts';
|
||||
import type { LandedFacts, Task } from './contract.ts';
|
||||
|
||||
@@ -21,7 +21,6 @@ export type TaskStore = {
|
||||
/** 活动装载 —— app 注入 `activity-registry`(L4) */
|
||||
export type ActivityLoader = {
|
||||
load(activityId: string): Promise<{
|
||||
paradigm: Paradigm;
|
||||
caps: BudgetCaps;
|
||||
envelope: Record<string, unknown>;
|
||||
/** 输入 data 的 JSON Schema —— 缺项不得启动 */
|
||||
|
||||
Reference in New Issue
Block a user