三面拆分⑬:触发确认链路 + 运营中心「工作流」区 —— 设计只管设计,运营管细节

**触发确认链路**(用户口述五步的第 4/5 步):
  接收邮件 → 分类识别 → 命中 RFQ 事件 → ④(可选,运营勾)系统消息到指定人
  工作台(带邮件内容)→ ⑤ 工作台点「确认起单」,流程才起。
  · 命中不等于必起:勾了「需人工确认」,装配好的入参存成待确认单
    (sys.trigger_pending,migration 0019),ConfirmDesk 端口把带来件内容的
    系统消息送指定人(eventRef 挂票号,消息列表就地贴确认状态与那枚钮)。
  · 先认领后起单:consumed_at 空才认得到 —— 两人同时点、一人点两次,都只起一条流;
    起单失败退回认领,不留死票。确认人记进 source.by,留痕可查。
  · 登记触发不走确认(登记那一下本身就是人在确认);勾了没指定人 = 配置错误入死信。
  · 4 条单测 + 全链实测:投信 → triggersHit=1 且零直起 → AI 工作台收到确认消息
    → 确认起单 → 二次确认幂等回同一流号 → source.by = AI。

**运营中心重排**(区名即运行时:工作流是流程包的运行时,任务是活动的运行时):
  · 新「工作流」区:在途看板(从任务区迁入)+ 运行配置 —— 每包的触发器
    起单开关 / 确认打勾 / 确认人,和节点负责人(sys.node_owner)。
  · 负责人三层:显式指派 > 运营配置 > 轮值 —— 合并点在 process.start,
    复用既有派发链一行不改。
  · 任务区瘦身成活动运行时(任务/审批/需处置);知识库区改名「数据」
    (与设计中心的知识库解开同名);系统区只剩通道实例。
  · 设计中心触发器详情页摘掉启停按钮 —— 设计只管设计,启停/确认全在运营。
  · 旧深链有改嫁:tasks/board → runs/board,tasks/trg → runs/conf。

reset-runs 补 sys.trigger_pending(待确认单是运行痕 —— 和上回漏 trace_span 同类洞)。
邮件分类 Agent(第 ② 步)现由抽键正则 + S-FEEL 代位,升级路径记进 debt.md。
产品设计.md 运营章、trigger/process 两份 CONTRACT.md 同步。

五闸绿;契约快照随本提交入库。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
2026-07-29 13:09:16 +08:00
co-authored by Claude Opus 5
parent 70b261d067
commit f9b2c07731
45 changed files with 1176 additions and 115 deletions
@@ -17,7 +17,6 @@ import type { TriggerConfig } from '@contracts';
import {
TRIGGER_KIND_LABEL,
processPackageIdSchema,
toggleTriggerRoute,
triggerKindOf,
upsertTriggerRoute,
} from '@contracts';
@@ -29,8 +28,6 @@ import {
Clear,
Field,
ListEdit,
NList,
NRow,
Note,
PageHead,
Prop,
@@ -394,62 +391,9 @@ function TriggerForm({
/* ==================== 运营侧:起单开关(处置面) ==================== */
export function TriggerOpsTab({ nav }: { nav: Nav }) {
const q = useGovTriggers();
const triggers = q.data?.triggers ?? [];
const toggle = useGovAction(
(input: { id: string; enabled: boolean }) =>
call(toggleTriggerRoute, { params: { id: input.id }, body: { enabled: input.enabled } }),
['triggers'],
);
return (
<QueryGate query={q}>
<>
<Note>
开关管的是<b>今天起不起单</b>,不是规则本身。停用后此后不再起新单,<b>已起的照常跑完</b>;
规则怎么写在设计中心 · 流程包 - 调起规则里改。
</Note>
{triggers.length === 0 ? (
<Clear>还没有调起规则 —— 设计中心配好之后,开关会出现在这里。</Clear>
) : (
<NList>
{triggers.map((t) => (
<NRow
key={t.id}
tone={t.enabled ? 'brand' : 'mute'}
ico="zap"
title={t.name}
sub={ruleText(t)}
cols={[
{ k: '类别', v: <Chip tone="brand">{TRIGGER_KIND_LABEL[triggerKindOf(t.spec)]}</Chip> },
{ k: '调起', v: t.processPackageId },
]}
right={
<St tone={t.enabled ? 'ok' : 'mute'} ico={t.enabled ? 'circle-check' : 'power'}>
{t.enabled ? '已启用' : '已停用'}
</St>
}
onClick={() => nav.push({ k: 'trigger', id: t.id })}
/>
))}
</NList>
)}
{toggle.isError && <Note tone="warn">切换失败,请重试。</Note>}
</>
</QueryGate>
);
}
/* ==================== 触发器详情(两面共用) ==================== */
export function TriggerPage({ id }: { id: string }) {
const q = useGovTriggers();
const t = (q.data?.triggers ?? []).find((x) => x.id === id);
const toggle = useGovAction(
(enabled: boolean) => call(toggleTriggerRoute, { params: { id }, body: { enabled } }),
['triggers'],
);
if (t === undefined) return <Note>触发器不存在。</Note>;
return (
<>
@@ -462,27 +406,13 @@ export function TriggerPage({ id }: { id: string }) {
<>
<Chip tone="brand">{TRIGGER_KIND_LABEL[triggerKindOf(t.spec)]}</Chip>
<Chip ico="boxes">调起 {t.processPackageId}</Chip>
<Chip tone={t.enabled ? 'ok' : 'mute'} ico="power">
{t.enabled ? '起单中' : '已停用'}
</Chip>
{t.confirm.required && <Chip tone="warn">命中须人工确认</Chip>}
</>
}
desc="触发器与流程包平级——不入包结构、不随包版本,增删启停不改任何版本。规则在设计中心改,开关在运营中心拨。"
acts={[
{
label: t.enabled ? '停用' : '启用',
ico: 'power',
danger: t.enabled,
ask: {
title: `${t.enabled ? '停用' : '启用'}触发器:${t.name}`,
note: <Note>启停不改任何版本;已起的单不受影响。</Note>,
impact: {
who: t.enabled ? '此后不再自动起单,已在途工作流不受影响' : '此后按规则自动起单',
undo: '可随时反向切换',
when: '确认后即时',
},
okLabel: t.enabled ? '确认停用' : '确认启用',
onOk: () => toggle.mutate(!t.enabled),
},
},
]}
desc="设计中心只负责设计:这里改的是规则与装配。启停开关、要不要人工确认、谁来确认,在运营中心 · 工作流的运行配置里。"
/>
<Card ico="settings" title="起单规则">
<Rows