feat(loop-engine): 拍首跑配方 —— 确定的活由引擎做完,剩下的才问模型

liveStepOf 从 turn-runner 提纯成纯函数(带 repetitionRule 的项收了仍 Enabled,
不跳过已收掉的就整单钉在第一步 —— 这条实测栽过)。
有卡在等人时配方照样跑但只算只写:人在件上按了保存,该铺的行就铺出来。
老活动一个字不用改:剧本里没有 auto,这一段整个不进。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
xcs
2026-08-29 04:28:18 +08:00
co-authored by Claude Opus 5
parent e9da8d25f5
commit fbd5867206
5 changed files with 281 additions and 4 deletions
@@ -0,0 +1,30 @@
import { describe, expect, it } from 'vitest';
import { liveStepOf } from '../internal/domain/live-step.ts';
const steps = [
{ item: 'S1', guide: '' },
{ item: 'S2', guide: '' },
{ item: 'T_release', guide: '' },
];
describe('liveStepOf:这一单此刻在办哪一步', () => {
it('在场的第一个还没收掉的项', () => {
expect(liveStepOf(steps, new Set(), [{ id: 'S1' }, { id: 'S2' }])?.item).toBe('S1');
});
it('**收掉的项要跳过** —— 带 repetitionRule 的项收了之后仍是 Enabled,不跳就整单钉在第一步', () => {
expect(liveStepOf(steps, new Set(['S1']), [{ id: 'S1' }, { id: 'S2' }])?.item).toBe('S2');
});
it('在场的都收完了 → undefined', () => {
expect(liveStepOf(steps, new Set(['S1', 'S2']), [{ id: 'S1' }, { id: 'S2' }])).toBeUndefined();
});
it('在场的项没有剧本 → undefined(没写剧本的活动照旧跑)', () => {
expect(liveStepOf(steps, new Set(), [{ id: 'X' }])).toBeUndefined();
});
it('次序按 onStage 给的次序,不按 steps 的次序', () => {
expect(liveStepOf(steps, new Set(), [{ id: 'S2' }, { id: 'S1' }])?.item).toBe('S2');
});
});