删掉聊天 reducer 里没人读的订阅身份与首屏锚点

- DirectThreadChatState 去掉 subscriptionId 与 lastCompletedItemId 两个只写不读的字段
- resolveDirectThreadBootstrap 只把 bootstrap 事件 reduce 进状态,不再顺带写入这两个字段
- directThreadChat 单测改成断言聊天状态里不再出现这两个字段(bootstrap 载荷本身不变)
This commit is contained in:
2026-09-17 00:05:57 +08:00
parent 098693636a
commit 1b40f030e7
2 changed files with 6 additions and 16 deletions
@@ -32,9 +32,6 @@ export type DirectChatEntry = {
};
export type DirectThreadChatState = {
subscriptionId: string | null;
/** 首屏历史锚点:`subscribe` 给出的最后一条完成条目 id。 */
lastCompletedItemId: string | null;
/** 最新回合是否还在跑;只由生命周期事件的先后决定。 */
turnRunning: boolean;
/** 历史切片条目,保持文件顺序。 */
@@ -45,8 +42,6 @@ export type DirectThreadChatState = {
export function emptyDirectThreadChatState(): DirectThreadChatState {
return {
subscriptionId: null,
lastCompletedItemId: null,
turnRunning: false,
history: [],
live: [],
@@ -197,20 +192,14 @@ export function reduceDirectThreadEvents(
/**
* bootstrap 是运行态的唯一权威:游标已在队尾,返回的事件就是此刻要处理的事件。
*
* 历史窗口保留:bootstrap 不重新回读历史切片,那是 `lastCompletedItemId` 的职责。
* 订阅身份与首屏历史锚点(`subscriptionId` / `lastCompletedItemId`)是订阅循环自己的局部
* 事实,不进聊天状态:这里只把 bootstrap 事件 reduce 进现有状态。
*/
export function resolveDirectThreadBootstrap(
state: DirectThreadChatState,
bootstrap: DirectThreadSubscriptionBootstrap,
): DirectThreadChatState {
return reduceDirectThreadEvents(
{
...state,
subscriptionId: bootstrap.subscriptionId,
lastCompletedItemId: bootstrap.lastCompletedItemId ?? null,
},
bootstrap.events,
);
return reduceDirectThreadEvents(state, bootstrap.events);
}
/** 事件顺序 = 游标顺序;调用方只需要把 `consume` 的结果喂进来。 */
@@ -80,8 +80,9 @@ describe('DirectProject 聊天 reducer', () => {
],
},
);
expect(bootstrapped.subscriptionId).toBe('sub-1');
expect(bootstrapped.lastCompletedItemId).toBe('msg-9');
// 订阅身份与首屏锚点由订阅循环自己持有,不写进聊天 reducer 状态。
expect(bootstrapped).not.toHaveProperty('subscriptionId');
expect(bootstrapped).not.toHaveProperty('lastCompletedItemId');
expect(bootstrapped.turnRunning).toBe(true);
expect(selectDirectChatEntries(bootstrapped)).toHaveLength(1);
});