基线:鉴权会话+工作组+工作台三区修复+编排工作区+产品设计文档

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
2026-07-27 20:43:35 +08:00
co-authored by Claude Fable 5
parent 61fe181678
commit ac85ecf2ea
119 changed files with 16634 additions and 1246 deletions
@@ -27,6 +27,7 @@ describe('planConsumption —— 三级消费', () => {
listenerHits: [{ taskId: 't1' }],
triggerHits: ['tr1'],
ownedTaskId: 't1',
hasOwner: true,
});
expect(plan.taskTargets).toEqual(['t1']);
expect(plan.triggerTargets).toEqual(['tr1']);
@@ -34,24 +35,42 @@ describe('planConsumption —— 三级消费', () => {
});
it('皆未命中且无主 → 消息兜底', () => {
const plan = planConsumption({ listenerHits: [], triggerHits: [], ownedTaskId: undefined });
const plan = planConsumption({ listenerHits: [], triggerHits: [], ownedTaskId: undefined, hasOwner: false });
expect(plan.messageFallback).toBe(true);
});
it('有主但零监听命中 → 仅记录,不兜底、不降级为无主', () => {
const plan = planConsumption({ listenerHits: [], triggerHits: [], ownedTaskId: 't7' });
const plan = planConsumption({ listenerHits: [], triggerHits: [], ownedTaskId: 't7', hasOwner: true });
expect(plan.messageFallback).toBe(false);
expect(plan.recordOnlyTask).toBe('t7');
expect(plan.taskTargets).toEqual([]);
});
it('主不是任务也算有主 —— 引擎发的工作流事件不得被当成无主件塞进收件箱', () => {
// 起单 / 解析负责人 / 起任务这些事件的 target 是 workflow,不是 task。
// 只认 ownedTaskId 的话,每起一单都会给人推一条「无主入站待认领」。
const plan = planConsumption({
listenerHits: [],
triggerHits: [],
ownedTaskId: undefined,
hasOwner: true,
});
expect(plan.messageFallback).toBe(false);
expect(plan.recordOnlyTask).toBeUndefined();
});
it('有主且监听命中 → 不是仅记录', () => {
const plan = planConsumption({ listenerHits: [{ taskId: 't7' }], triggerHits: [], ownedTaskId: 't7' });
const plan = planConsumption({
listenerHits: [{ taskId: 't7' }],
triggerHits: [],
ownedTaskId: 't7',
hasOwner: true,
});
expect(plan.recordOnlyTask).toBeUndefined();
});
it('无主但触发命中 → 不兜底', () => {
const plan = planConsumption({ listenerHits: [], triggerHits: ['tr1'], ownedTaskId: undefined });
const plan = planConsumption({ listenerHits: [], triggerHits: ['tr1'], ownedTaskId: undefined, hasOwner: false });
expect(plan.messageFallback).toBe(false);
});
});
@@ -58,6 +58,14 @@ export function planConsumption(input: {
readonly listenerHits: ReadonlyArray<{ taskId: string }>;
readonly triggerHits: readonly string[];
readonly ownedTaskId: string | undefined;
/**
* 信封是否**有主** —— 关联里指了目标就算有主,不限于任务。
*
* 不能拿「有没有 ownedTaskId」当有主:引擎自己发的工作流事件
* (`target: { kind: 'workflow' }`)照样是有主的,只是主不是任务。
* 把它们判成无主,等于把每次起单都当成「没人认领的入站件」塞进别人收件箱。
*/
readonly hasOwner: boolean;
}): ConsumptionPlan {
const taskTargets = fanOutTargets(input.listenerHits);
const triggerTargets = [...new Set(input.triggerHits)];
@@ -65,8 +73,8 @@ export function planConsumption(input: {
return {
taskTargets,
triggerTargets,
// 有主但零监听命中 → 仅记录,不兜底
messageFallback: nothingHit && input.ownedTaskId === undefined,
// 有主但零监听命中 → 仅记录,不兜底;消息只兜**真正无主**的件(OS 6.3)
messageFallback: nothingHit && !input.hasOwner,
recordOnlyTask:
input.ownedTaskId !== undefined && !taskTargets.includes(input.ownedTaskId)
? input.ownedTaskId
@@ -46,7 +46,12 @@ export function createEventService(deps: EventServiceDeps): EventService {
const ownedTaskId =
envelope.correlation.target?.kind === 'task' ? String(envelope.correlation.target.id) : undefined;
const plan = planConsumption({ listenerHits: hits, triggerHits, ownedTaskId });
const plan = planConsumption({
listenerHits: hits,
triggerHits,
ownedTaskId,
hasOwner: envelope.correlation.target !== undefined,
});
// 扇出:每个命中目标一份独立投递,信封「关联 = 单目标」保持单目标
const deliveries: Delivery[] = [